├── .github ├── FUNDING.yml └── workflows │ ├── gmic-blender-addon-test.yml │ └── makecrossplatformrelease.yml ├── .gitignore ├── CI_simple_local_test.sh ├── COPYING ├── README.md ├── __init__.py ├── assets ├── .gitignore ├── bak │ ├── fixjson.bash │ ├── gmic_filters.json │ └── gmic_filters_fixed.json └── gmic_filters.json ├── blender_addon_tester_requirements.txt ├── examples ├── A4-flipbook-from-rendered-files │ └── flipbookpostgmic.py ├── gmic-example-effects-operators-simple-menu │ └── ExampleGmicEffectsMenu.py └── gmic-filters-default-parameters-to-operators │ ├── README.md │ ├── bpy_operators_scripts.py │ ├── default_parameters_gmic_py.py │ ├── filters290.json │ └── make_operators.py ├── get_latest_gmicpy_version.py ├── make_addon_requirements.txt ├── make_addon_zip.py ├── test_gmic_blender_addon.py └── tests └── test_version_and_gmicpy_import.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://libreart.info/en/projects/gmic 2 | -------------------------------------------------------------------------------- /.github/workflows/gmic-blender-addon-test.yml: -------------------------------------------------------------------------------- 1 | name: gmic-blender-testing 2 | 3 | on: 4 | push: 5 | schedule: 6 | - cron: '0 0 * * *' 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | max-parallel: 4 14 | matrix: 15 | blender-version: ["2.80", "2.81a", "2.82a", "2.83.0", "2.90.0"] 16 | os: [ubuntu-latest, macos-latest] #, windows-latest] 17 | env: 18 | BLENDER_CACHE: ${{ github.workspace }}/.blender_releases_cache # The place where blender releases are downloaded 19 | BLENDER_VERSION: ${{ matrix.blender-version }} 20 | GMICPY_DOWNLOADS_CACHE: ${{ github.workspace }}/.gmicpy_wheels_cache # The place where blender releases are downloaded 21 | 22 | steps: 23 | - uses: actions/checkout@v1 24 | - name: Set up Python 25 | uses: actions/setup-python@v1 26 | with: 27 | python-version: 3.7 28 | - name: Install python requirements and set latest gmic-py version into env 29 | run: | 30 | pip install -r make_addon_requirements.txt 31 | echo ::set-env name=GMICPYVERSION::$(python get_latest_gmicpy_version.py) 32 | - name: Cache Gmic Python ${{ env.GMICPYVERSION }} all-platforms wheels download 33 | uses: actions/cache@v1 34 | with: 35 | path: ${{ env.GMICPY_DOWNLOADS_CACHE }} 36 | key: gmic-py-${{ env.GMICPYVERSION }} 37 | - name: Cache ${{ matrix.os }} Blender ${{ matrix.blender-version }} release download 38 | uses: actions/cache@v1 39 | with: 40 | path: ${{ env.BLENDER_CACHE }} 41 | key: ${{ matrix.os }}-blender-${{ matrix.blender-version }} 42 | - name: Install MacOSX fftw and libomp with Homebrew 43 | if: matrix.os == 'macos-latest' 44 | run: | 45 | brew install fftw libomp 46 | - name: Grab Blender ${{ matrix.blender-version }}, build gmic-blender ${{ env.GMICPYVERSION }} and test them with pytest 47 | run: | 48 | python make_addon_zip.py 49 | pip install -r blender_addon_tester_requirements.txt 50 | python test_gmic_blender_addon.py # Uses the BLENDER_VERSION environment variable 51 | - name: Expose coverage as a CI download 52 | uses: actions/upload-artifact@v1 53 | with: 54 | name: ${{ matrix.os }}-blender-${{ matrix.blender-version }}-coverage.xml 55 | path: coverage.xml 56 | -------------------------------------------------------------------------------- /.github/workflows/makecrossplatformrelease.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | # Sequence of patterns matched against refs/tags 4 | tags: 5 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 6 | 7 | name: Upload Release Asset 8 | 9 | jobs: 10 | build: 11 | name: Upload Release Asset 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | - name: Set env 17 | run: echo ::set-env name=RELEASE_VERSION::${GITHUB_REF:10} 18 | - name: Set up Python 19 | uses: actions/setup-python@v1 20 | with: 21 | python-version: 3.7 22 | - name: Install Python requirements 23 | run: pip install -r make_addon_requirements.txt 24 | - name: Set latest gmic-py version into env 25 | run: echo ::set-env name=GMICPYVERSION::$(python get_latest_gmicpy_version.py) 26 | - name: Build Add-On ${{ github.ref }} x gmic-py ${{ env.GMICPYVERSION }} # This would actually build your project, using zip for an example artifact 27 | run: python make_addon_zip.py 28 | - name: Create Release 29 | id: create_release 30 | uses: actions/create-release@v1 31 | env: 32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | with: 34 | tag_name: ${{ github.ref }} 35 | release_name: Release ${{ github.ref }} 36 | draft: false 37 | prerelease: true 38 | - name: Upload Release Asset 39 | id: upload-release-asset 40 | uses: actions/upload-release-asset@v1 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | with: 44 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 45 | asset_path: ./downloads/gmic_blender.zip 46 | asset_name: gmic_blender-${{ env.RELEASE_VERSION }}-gmicpy-${{ env.GMICPYVERSION }}.zip 47 | asset_content_type: application/zip 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage.xml 2 | .coverage 3 | downloads 4 | gmic-py 5 | tests/__pycache__ 6 | -------------------------------------------------------------------------------- /CI_simple_local_test.sh: -------------------------------------------------------------------------------- 1 | pip install -r make_addon_requirements.txt 2 | python make_addon_zip.py 3 | pip install -r blender_addon_tester_requirements.txt 4 | python test_gmic_blender_addon.py # Uses the BLENDER_VERSION environment variable 5 | 6 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | CeCILL FREE SOFTWARE LICENSE AGREEMENT 3 | 4 | Version 2.1 dated 2013-06-21 5 | 6 | 7 | Notice 8 | 9 | This Agreement is a Free Software license agreement that is the result 10 | of discussions between its authors in order to ensure compliance with 11 | the two main principles guiding its drafting: 12 | 13 | * firstly, compliance with the principles governing the distribution 14 | of Free Software: access to source code, broad rights granted to users, 15 | * secondly, the election of a governing law, French law, with which it 16 | is conformant, both as regards the law of torts and intellectual 17 | property law, and the protection that it offers to both authors and 18 | holders of the economic rights over software. 19 | 20 | The authors of the CeCILL (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre]) 21 | license are: 22 | 23 | Commissariat à l'énergie atomique et aux énergies alternatives - CEA, a 24 | public scientific, technical and industrial research establishment, 25 | having its principal place of business at 25 rue Leblanc, immeuble Le 26 | Ponant D, 75015 Paris, France. 27 | 28 | Centre National de la Recherche Scientifique - CNRS, a public scientific 29 | and technological establishment, having its principal place of business 30 | at 3 rue Michel-Ange, 75794 Paris cedex 16, France. 31 | 32 | Institut National de Recherche en Informatique et en Automatique - 33 | Inria, a public scientific and technological establishment, having its 34 | principal place of business at Domaine de Voluceau, Rocquencourt, BP 35 | 105, 78153 Le Chesnay cedex, France. 36 | 37 | 38 | Preamble 39 | 40 | The purpose of this Free Software license agreement is to grant users 41 | the right to modify and redistribute the software governed by this 42 | license within the framework of an open source distribution model. 43 | 44 | The exercising of this right is conditional upon certain obligations for 45 | users so as to preserve this status for all subsequent redistributions. 46 | 47 | In consideration of access to the source code and the rights to copy, 48 | modify and redistribute granted by the license, users are provided only 49 | with a limited warranty and the software's author, the holder of the 50 | economic rights, and the successive licensors only have limited liability. 51 | 52 | In this respect, the risks associated with loading, using, modifying 53 | and/or developing or reproducing the software by the user are brought to 54 | the user's attention, given its Free Software status, which may make it 55 | complicated to use, with the result that its use is reserved for 56 | developers and experienced professionals having in-depth computer 57 | knowledge. Users are therefore encouraged to load and test the 58 | suitability of the software as regards their requirements in conditions 59 | enabling the security of their systems and/or data to be ensured and, 60 | more generally, to use and operate it in the same conditions of 61 | security. This Agreement may be freely reproduced and published, 62 | provided it is not altered, and that no provisions are either added or 63 | removed herefrom. 64 | 65 | This Agreement may apply to any or all software for which the holder of 66 | the economic rights decides to submit the use thereof to its provisions. 67 | 68 | Frequently asked questions can be found on the official website of the 69 | CeCILL licenses family (http://www.cecill.info/index.en.html) for any 70 | necessary clarification. 71 | 72 | 73 | Article 1 - DEFINITIONS 74 | 75 | For the purpose of this Agreement, when the following expressions 76 | commence with a capital letter, they shall have the following meaning: 77 | 78 | Agreement: means this license agreement, and its possible subsequent 79 | versions and annexes. 80 | 81 | Software: means the software in its Object Code and/or Source Code form 82 | and, where applicable, its documentation, "as is" when the Licensee 83 | accepts the Agreement. 84 | 85 | Initial Software: means the Software in its Source Code and possibly its 86 | Object Code form and, where applicable, its documentation, "as is" when 87 | it is first distributed under the terms and conditions of the Agreement. 88 | 89 | Modified Software: means the Software modified by at least one 90 | Contribution. 91 | 92 | Source Code: means all the Software's instructions and program lines to 93 | which access is required so as to modify the Software. 94 | 95 | Object Code: means the binary files originating from the compilation of 96 | the Source Code. 97 | 98 | Holder: means the holder(s) of the economic rights over the Initial 99 | Software. 100 | 101 | Licensee: means the Software user(s) having accepted the Agreement. 102 | 103 | Contributor: means a Licensee having made at least one Contribution. 104 | 105 | Licensor: means the Holder, or any other individual or legal entity, who 106 | distributes the Software under the Agreement. 107 | 108 | Contribution: means any or all modifications, corrections, translations, 109 | adaptations and/or new functions integrated into the Software by any or 110 | all Contributors, as well as any or all Internal Modules. 111 | 112 | Module: means a set of sources files including their documentation that 113 | enables supplementary functions or services in addition to those offered 114 | by the Software. 115 | 116 | External Module: means any or all Modules, not derived from the 117 | Software, so that this Module and the Software run in separate address 118 | spaces, with one calling the other when they are run. 119 | 120 | Internal Module: means any or all Module, connected to the Software so 121 | that they both execute in the same address space. 122 | 123 | GNU GPL: means the GNU General Public License version 2 or any 124 | subsequent version, as published by the Free Software Foundation Inc. 125 | 126 | GNU Affero GPL: means the GNU Affero General Public License version 3 or 127 | any subsequent version, as published by the Free Software Foundation Inc. 128 | 129 | EUPL: means the European Union Public License version 1.1 or any 130 | subsequent version, as published by the European Commission. 131 | 132 | Parties: mean both the Licensee and the Licensor. 133 | 134 | These expressions may be used both in singular and plural form. 135 | 136 | 137 | Article 2 - PURPOSE 138 | 139 | The purpose of the Agreement is the grant by the Licensor to the 140 | Licensee of a non-exclusive, transferable and worldwide license for the 141 | Software as set forth in Article 5 <#scope> hereinafter for the whole 142 | term of the protection granted by the rights over said Software. 143 | 144 | 145 | Article 3 - ACCEPTANCE 146 | 147 | 3.1 The Licensee shall be deemed as having accepted the terms and 148 | conditions of this Agreement upon the occurrence of the first of the 149 | following events: 150 | 151 | * (i) loading the Software by any or all means, notably, by 152 | downloading from a remote server, or by loading from a physical medium; 153 | * (ii) the first time the Licensee exercises any of the rights granted 154 | hereunder. 155 | 156 | 3.2 One copy of the Agreement, containing a notice relating to the 157 | characteristics of the Software, to the limited warranty, and to the 158 | fact that its use is restricted to experienced users has been provided 159 | to the Licensee prior to its acceptance as set forth in Article 3.1 160 | <#accepting> hereinabove, and the Licensee hereby acknowledges that it 161 | has read and understood it. 162 | 163 | 164 | Article 4 - EFFECTIVE DATE AND TERM 165 | 166 | 167 | 4.1 EFFECTIVE DATE 168 | 169 | The Agreement shall become effective on the date when it is accepted by 170 | the Licensee as set forth in Article 3.1 <#accepting>. 171 | 172 | 173 | 4.2 TERM 174 | 175 | The Agreement shall remain in force for the entire legal term of 176 | protection of the economic rights over the Software. 177 | 178 | 179 | Article 5 - SCOPE OF RIGHTS GRANTED 180 | 181 | The Licensor hereby grants to the Licensee, who accepts, the following 182 | rights over the Software for any or all use, and for the term of the 183 | Agreement, on the basis of the terms and conditions set forth hereinafter. 184 | 185 | Besides, if the Licensor owns or comes to own one or more patents 186 | protecting all or part of the functions of the Software or of its 187 | components, the Licensor undertakes not to enforce the rights granted by 188 | these patents against successive Licensees using, exploiting or 189 | modifying the Software. If these patents are transferred, the Licensor 190 | undertakes to have the transferees subscribe to the obligations set 191 | forth in this paragraph. 192 | 193 | 194 | 5.1 RIGHT OF USE 195 | 196 | The Licensee is authorized to use the Software, without any limitation 197 | as to its fields of application, with it being hereinafter specified 198 | that this comprises: 199 | 200 | 1. permanent or temporary reproduction of all or part of the Software 201 | by any or all means and in any or all form. 202 | 203 | 2. loading, displaying, running, or storing the Software on any or all 204 | medium. 205 | 206 | 3. entitlement to observe, study or test its operation so as to 207 | determine the ideas and principles behind any or all constituent 208 | elements of said Software. This shall apply when the Licensee 209 | carries out any or all loading, displaying, running, transmission or 210 | storage operation as regards the Software, that it is entitled to 211 | carry out hereunder. 212 | 213 | 214 | 5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS 215 | 216 | The right to make Contributions includes the right to translate, adapt, 217 | arrange, or make any or all modifications to the Software, and the right 218 | to reproduce the resulting software. 219 | 220 | The Licensee is authorized to make any or all Contributions to the 221 | Software provided that it includes an explicit notice that it is the 222 | author of said Contribution and indicates the date of the creation thereof. 223 | 224 | 225 | 5.3 RIGHT OF DISTRIBUTION 226 | 227 | In particular, the right of distribution includes the right to publish, 228 | transmit and communicate the Software to the general public on any or 229 | all medium, and by any or all means, and the right to market, either in 230 | consideration of a fee, or free of charge, one or more copies of the 231 | Software by any means. 232 | 233 | The Licensee is further authorized to distribute copies of the modified 234 | or unmodified Software to third parties according to the terms and 235 | conditions set forth hereinafter. 236 | 237 | 238 | 5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION 239 | 240 | The Licensee is authorized to distribute true copies of the Software in 241 | Source Code or Object Code form, provided that said distribution 242 | complies with all the provisions of the Agreement and is accompanied by: 243 | 244 | 1. a copy of the Agreement, 245 | 246 | 2. a notice relating to the limitation of both the Licensor's warranty 247 | and liability as set forth in Articles 8 and 9, 248 | 249 | and that, in the event that only the Object Code of the Software is 250 | redistributed, the Licensee allows effective access to the full Source 251 | Code of the Software for a period of at least three years from the 252 | distribution of the Software, it being understood that the additional 253 | acquisition cost of the Source Code shall not exceed the cost of the 254 | data transfer. 255 | 256 | 257 | 5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE 258 | 259 | When the Licensee makes a Contribution to the Software, the terms and 260 | conditions for the distribution of the resulting Modified Software 261 | become subject to all the provisions of this Agreement. 262 | 263 | The Licensee is authorized to distribute the Modified Software, in 264 | source code or object code form, provided that said distribution 265 | complies with all the provisions of the Agreement and is accompanied by: 266 | 267 | 1. a copy of the Agreement, 268 | 269 | 2. a notice relating to the limitation of both the Licensor's warranty 270 | and liability as set forth in Articles 8 and 9, 271 | 272 | and, in the event that only the object code of the Modified Software is 273 | redistributed, 274 | 275 | 3. a note stating the conditions of effective access to the full source 276 | code of the Modified Software for a period of at least three years 277 | from the distribution of the Modified Software, it being understood 278 | that the additional acquisition cost of the source code shall not 279 | exceed the cost of the data transfer. 280 | 281 | 282 | 5.3.3 DISTRIBUTION OF EXTERNAL MODULES 283 | 284 | When the Licensee has developed an External Module, the terms and 285 | conditions of this Agreement do not apply to said External Module, that 286 | may be distributed under a separate license agreement. 287 | 288 | 289 | 5.3.4 COMPATIBILITY WITH OTHER LICENSES 290 | 291 | The Licensee can include a code that is subject to the provisions of one 292 | of the versions of the GNU GPL, GNU Affero GPL and/or EUPL in the 293 | Modified or unmodified Software, and distribute that entire code under 294 | the terms of the same version of the GNU GPL, GNU Affero GPL and/or EUPL. 295 | 296 | The Licensee can include the Modified or unmodified Software in a code 297 | that is subject to the provisions of one of the versions of the GNU GPL, 298 | GNU Affero GPL and/or EUPL and distribute that entire code under the 299 | terms of the same version of the GNU GPL, GNU Affero GPL and/or EUPL. 300 | 301 | 302 | Article 6 - INTELLECTUAL PROPERTY 303 | 304 | 305 | 6.1 OVER THE INITIAL SOFTWARE 306 | 307 | The Holder owns the economic rights over the Initial Software. Any or 308 | all use of the Initial Software is subject to compliance with the terms 309 | and conditions under which the Holder has elected to distribute its work 310 | and no one shall be entitled to modify the terms and conditions for the 311 | distribution of said Initial Software. 312 | 313 | The Holder undertakes that the Initial Software will remain ruled at 314 | least by this Agreement, for the duration set forth in Article 4.2 <#term>. 315 | 316 | 317 | 6.2 OVER THE CONTRIBUTIONS 318 | 319 | The Licensee who develops a Contribution is the owner of the 320 | intellectual property rights over this Contribution as defined by 321 | applicable law. 322 | 323 | 324 | 6.3 OVER THE EXTERNAL MODULES 325 | 326 | The Licensee who develops an External Module is the owner of the 327 | intellectual property rights over this External Module as defined by 328 | applicable law and is free to choose the type of agreement that shall 329 | govern its distribution. 330 | 331 | 332 | 6.4 JOINT PROVISIONS 333 | 334 | The Licensee expressly undertakes: 335 | 336 | 1. not to remove, or modify, in any manner, the intellectual property 337 | notices attached to the Software; 338 | 339 | 2. to reproduce said notices, in an identical manner, in the copies of 340 | the Software modified or not. 341 | 342 | The Licensee undertakes not to directly or indirectly infringe the 343 | intellectual property rights on the Software of the Holder and/or 344 | Contributors, and to take, where applicable, vis-à-vis its staff, any 345 | and all measures required to ensure respect of said intellectual 346 | property rights of the Holder and/or Contributors. 347 | 348 | 349 | Article 7 - RELATED SERVICES 350 | 351 | 7.1 Under no circumstances shall the Agreement oblige the Licensor to 352 | provide technical assistance or maintenance services for the Software. 353 | 354 | However, the Licensor is entitled to offer this type of services. The 355 | terms and conditions of such technical assistance, and/or such 356 | maintenance, shall be set forth in a separate instrument. Only the 357 | Licensor offering said maintenance and/or technical assistance services 358 | shall incur liability therefor. 359 | 360 | 7.2 Similarly, any Licensor is entitled to offer to its licensees, under 361 | its sole responsibility, a warranty, that shall only be binding upon 362 | itself, for the redistribution of the Software and/or the Modified 363 | Software, under terms and conditions that it is free to decide. Said 364 | warranty, and the financial terms and conditions of its application, 365 | shall be subject of a separate instrument executed between the Licensor 366 | and the Licensee. 367 | 368 | 369 | Article 8 - LIABILITY 370 | 371 | 8.1 Subject to the provisions of Article 8.2, the Licensee shall be 372 | entitled to claim compensation for any direct loss it may have suffered 373 | from the Software as a result of a fault on the part of the relevant 374 | Licensor, subject to providing evidence thereof. 375 | 376 | 8.2 The Licensor's liability is limited to the commitments made under 377 | this Agreement and shall not be incurred as a result of in particular: 378 | (i) loss due the Licensee's total or partial failure to fulfill its 379 | obligations, (ii) direct or consequential loss that is suffered by the 380 | Licensee due to the use or performance of the Software, and (iii) more 381 | generally, any consequential loss. In particular the Parties expressly 382 | agree that any or all pecuniary or business loss (i.e. loss of data, 383 | loss of profits, operating loss, loss of customers or orders, 384 | opportunity cost, any disturbance to business activities) or any or all 385 | legal proceedings instituted against the Licensee by a third party, 386 | shall constitute consequential loss and shall not provide entitlement to 387 | any or all compensation from the Licensor. 388 | 389 | 390 | Article 9 - WARRANTY 391 | 392 | 9.1 The Licensee acknowledges that the scientific and technical 393 | state-of-the-art when the Software was distributed did not enable all 394 | possible uses to be tested and verified, nor for the presence of 395 | possible defects to be detected. In this respect, the Licensee's 396 | attention has been drawn to the risks associated with loading, using, 397 | modifying and/or developing and reproducing the Software which are 398 | reserved for experienced users. 399 | 400 | The Licensee shall be responsible for verifying, by any or all means, 401 | the suitability of the product for its requirements, its good working 402 | order, and for ensuring that it shall not cause damage to either persons 403 | or properties. 404 | 405 | 9.2 The Licensor hereby represents, in good faith, that it is entitled 406 | to grant all the rights over the Software (including in particular the 407 | rights set forth in Article 5 <#scope>). 408 | 409 | 9.3 The Licensee acknowledges that the Software is supplied "as is" by 410 | the Licensor without any other express or tacit warranty, other than 411 | that provided for in Article 9.2 <#good-faith> and, in particular, 412 | without any warranty as to its commercial value, its secured, safe, 413 | innovative or relevant nature. 414 | 415 | Specifically, the Licensor does not warrant that the Software is free 416 | from any error, that it will operate without interruption, that it will 417 | be compatible with the Licensee's own equipment and software 418 | configuration, nor that it will meet the Licensee's requirements. 419 | 420 | 9.4 The Licensor does not either expressly or tacitly warrant that the 421 | Software does not infringe any third party intellectual property right 422 | relating to a patent, software or any other property right. Therefore, 423 | the Licensor disclaims any and all liability towards the Licensee 424 | arising out of any or all proceedings for infringement that may be 425 | instituted in respect of the use, modification and redistribution of the 426 | Software. Nevertheless, should such proceedings be instituted against 427 | the Licensee, the Licensor shall provide it with technical and legal 428 | expertise for its defense. Such technical and legal expertise shall be 429 | decided on a case-by-case basis between the relevant Licensor and the 430 | Licensee pursuant to a memorandum of understanding. The Licensor 431 | disclaims any and all liability as regards the Licensee's use of the 432 | name of the Software. No warranty is given as regards the existence of 433 | prior rights over the name of the Software or as regards the existence 434 | of a trademark. 435 | 436 | 437 | Article 10 - TERMINATION 438 | 439 | 10.1 In the event of a breach by the Licensee of its obligations 440 | hereunder, the Licensor may automatically terminate this Agreement 441 | thirty (30) days after notice has been sent to the Licensee and has 442 | remained ineffective. 443 | 444 | 10.2 A Licensee whose Agreement is terminated shall no longer be 445 | authorized to use, modify or distribute the Software. However, any 446 | licenses that it may have granted prior to termination of the Agreement 447 | shall remain valid subject to their having been granted in compliance 448 | with the terms and conditions hereof. 449 | 450 | 451 | Article 11 - MISCELLANEOUS 452 | 453 | 454 | 11.1 EXCUSABLE EVENTS 455 | 456 | Neither Party shall be liable for any or all delay, or failure to 457 | perform the Agreement, that may be attributable to an event of force 458 | majeure, an act of God or an outside cause, such as defective 459 | functioning or interruptions of the electricity or telecommunications 460 | networks, network paralysis following a virus attack, intervention by 461 | government authorities, natural disasters, water damage, earthquakes, 462 | fire, explosions, strikes and labor unrest, war, etc. 463 | 464 | 11.2 Any failure by either Party, on one or more occasions, to invoke 465 | one or more of the provisions hereof, shall under no circumstances be 466 | interpreted as being a waiver by the interested Party of its right to 467 | invoke said provision(s) subsequently. 468 | 469 | 11.3 The Agreement cancels and replaces any or all previous agreements, 470 | whether written or oral, between the Parties and having the same 471 | purpose, and constitutes the entirety of the agreement between said 472 | Parties concerning said purpose. No supplement or modification to the 473 | terms and conditions hereof shall be effective as between the Parties 474 | unless it is made in writing and signed by their duly authorized 475 | representatives. 476 | 477 | 11.4 In the event that one or more of the provisions hereof were to 478 | conflict with a current or future applicable act or legislative text, 479 | said act or legislative text shall prevail, and the Parties shall make 480 | the necessary amendments so as to comply with said act or legislative 481 | text. All other provisions shall remain effective. Similarly, invalidity 482 | of a provision of the Agreement, for any reason whatsoever, shall not 483 | cause the Agreement as a whole to be invalid. 484 | 485 | 486 | 11.5 LANGUAGE 487 | 488 | The Agreement is drafted in both French and English and both versions 489 | are deemed authentic. 490 | 491 | 492 | Article 12 - NEW VERSIONS OF THE AGREEMENT 493 | 494 | 12.1 Any person is authorized to duplicate and distribute copies of this 495 | Agreement. 496 | 497 | 12.2 So as to ensure coherence, the wording of this Agreement is 498 | protected and may only be modified by the authors of the License, who 499 | reserve the right to periodically publish updates or new versions of the 500 | Agreement, each with a separate number. These subsequent versions may 501 | address new issues encountered by Free Software. 502 | 503 | 12.3 Any Software distributed under a given version of the Agreement may 504 | only be subsequently distributed under the same version of the Agreement 505 | or a subsequent version, subject to the provisions of Article 5.3.4 506 | <#compatibility>. 507 | 508 | 509 | Article 13 - GOVERNING LAW AND JURISDICTION 510 | 511 | 13.1 The Agreement is governed by French law. The Parties agree to 512 | endeavor to seek an amicable solution to any disagreements or disputes 513 | that may arise during the performance of the Agreement. 514 | 515 | 13.2 Failing an amicable solution within two (2) months as from their 516 | occurrence, and unless emergency proceedings are necessary, the 517 | disagreements or disputes shall be referred to the Paris Courts having 518 | jurisdiction, by the more diligent Party. 519 | 520 | 521 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![G'MIC Logo](https://gmic.eu/img/logo4.jpg) 2 | ![Blender3d Logo](https://download.blender.org/branding/blender_logo_socket.png) 3 | 4 | #### 5 | #### Blender 3d Add-on for G'MIC - A Full-Featured Open-Source Framework for Image Processing 6 | ##### https://gmic.eu 7 | # gmic-blender 8 | 9 | 10 | This WIP official G'MIC plugin for [Blender3D 2.8x](https://www.blender.org/) uses the [G'MIC Python binding](https://github.com/dtschump/gmic-py) and will add new Nodes to Blender3d without forking Blender's code. This project is under the CeCILL-A free software license. 11 | 12 | Estimated time of arrival of 1 first generic Node: September 2020. 13 | 14 | This is being worked on at the [GREYC](https://www.greyc.fr/) Image public research laboratory in Caen, France, with temporary funding by the [INS2I CNRS Information & Interaction Sciences Institute](https://ins2i.cnrs.fr/fr/institut). 15 | 16 | ## Installing 17 | [The latest version is v0.0.8 embedding gmic-py 2.9.0.](https://github.com/myselfhimself/gmic-blender/issues/15) 18 | 19 | For now, gmic can be imported from Blender's Python :) The addon should work on Linux and MacOS. 20 | On MacOS you may need to install libomp and fftw first yourself using Homebrew: `brew install libomp fftw`. 21 | 1. [Head over to the Releases section and download an early zip addon archive.](https://github.com/myselfhimself/gmic-blender/releases) 22 | 1. [Add the gmic-blender addon .zip to Blender as a 3rd-party addon.](https://docs.blender.org/manual/en/latest/editors/preferences/addons.html#rd-party-add-ons) 23 | 1. [Open up a text editor view into Blender](https://docs.blender.org/manual/en/latest/editors/text_editor.html), type "import gmic" and execute it with `Alt+P`. 24 | 25 | ## Test Driven Development 26 | We are using a Blender Python Pytest framework named [blender-addon-tester](https://github.com/douglaskastle/blender-addon-tester). 27 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Blender G'MIC Add-on", 3 | "author": "Jonathan-David Schröder", 4 | "blender": (2, 80, 0), 5 | "version": (0, 0, 2), 6 | "category": "Object", 7 | } 8 | 9 | import os 10 | import sys 11 | import platform 12 | 13 | # TODO ensure that globals are tolerated in Blender3d python scripting guidelines.. 14 | __GMIC_ADDON_ROOT_PATH = os.path.abspath(os.path.dirname(__file__)) 15 | __GMIC_FILTERS_JSON_PATH = os.path.join(__GMIC_ADDON_ROOT_PATH, "assets", "gmic_filters.json") 16 | __GMIC_LOADED__ = False 17 | __GMIC_PY_RELATIVE_LIBS_DIR = "-".join([platform.system().lower(), platform.architecture()[0]]) 18 | 19 | def register(): 20 | print("Registering " + bl_info["name"]) 21 | if not load_gmic_binary_library(): 22 | print("Failed loading G'MIC binary library :-(") 23 | else: 24 | import gmic 25 | print(dir(gmic)) 26 | generate_nodes_from_gmic_filters(load_gmic_filters()) 27 | 28 | def unregister(): 29 | print("Unregistring " + bl_info["name"]) 30 | 31 | def load_gmic_binary_library(): 32 | global __GMIC_LOADED__ 33 | 34 | if __GMIC_LOADED__: 35 | return True 36 | 37 | __GMIC_LOADED__ = False 38 | 39 | import os 40 | import sys 41 | libdir = os.path.join(__GMIC_ADDON_ROOT_PATH, __GMIC_PY_RELATIVE_LIBS_DIR) 42 | if libdir not in sys.path: 43 | sys.path.insert(0, libdir) 44 | print("Added libdir to sys.path:", libdir) 45 | 46 | try: 47 | print("trying gmic import") 48 | import gmic 49 | print("gmic import worked") 50 | __GMIC_LOADED__ = True 51 | except ImportError as err: 52 | raise ImportError("Cannot load G'MIC binary python module at {}. Details: {}".format(libdir, sys.exc_info()[0])) 53 | 54 | try: 55 | type(gmic.Gmic) == type 56 | except AttributeError as err: 57 | raise ImportError("G'MIC binary Python module was loaded improperly from {} and is without symbols. Details: {}".format(libdir, sys.exc_info()[0])) 58 | 59 | return __GMIC_LOADED__ 60 | 61 | def load_gmic_filters(): 62 | import json 63 | # TODO add cache? // mtime check? 64 | filters_json = None 65 | # TODO catch exception and make a nice error pop-in if open this file fails 66 | with open(__GMIC_FILTERS_JSON_PATH) as f: 67 | filters_json = f.read() 68 | return json.loads(filters_json) 69 | 70 | def generate_nodes_from_gmic_filters(gmic_filters_dict): 71 | print("Loaded gmic_filters JSON overview:", gmic_filters_dict["format_version"], gmic_filters_dict["gmic_version"], "categories:", len(gmic_filters_dict["categories"])) 72 | print("") 73 | # TODO foreach loop on dict, create 1 node by filter 74 | -------------------------------------------------------------------------------- /assets/.gitignore: -------------------------------------------------------------------------------- 1 | bak 2 | -------------------------------------------------------------------------------- /assets/bak/fixjson.bash: -------------------------------------------------------------------------------- 1 | iconv -f ISO-8859-1 -t UTF-8//TRANSLIT gmic_filters.json -o gmic_filters.json2 2 | cat gmic_filters.json2 | python3 -c 'import html, sys; [print(html.unescape(l), end="") for l in sys.stdin]' > gmic_filters.json3 3 | rm gmic_filters.json2 4 | jsonlint-php gmic_filters.json3 && mv gmic_filters.json3 gmic_filters_fixed.json 5 | -------------------------------------------------------------------------------- /assets/bak/gmic_filters.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myselfhimself/gmic-blender/990324e645c56f4e2ef851d5b6ff99e8c28cc30b/assets/bak/gmic_filters.json -------------------------------------------------------------------------------- /blender_addon_tester_requirements.txt: -------------------------------------------------------------------------------- 1 | blender-addon-tester 2 | -------------------------------------------------------------------------------- /examples/A4-flipbook-from-rendered-files/flipbookpostgmic.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import os 3 | import os.path 4 | import gmic 5 | 6 | rendering_dir = os.path.dirname(bpy.context.scene.render.filepath) 7 | 8 | g = gmic.Gmic() 9 | 10 | good_filenames = [] 11 | for filename in os.listdir(rendering_dir): 12 | if filename.startswith("engraved"): 13 | print(filename) 14 | good_filenames.append(os.path.join(rendering_dir, filename)) 15 | 16 | print(good_filenames) 17 | g.run(" ".join(good_filenames) + " append_tiles , display") 18 | -------------------------------------------------------------------------------- /examples/gmic-example-effects-operators-simple-menu/ExampleGmicEffectsMenu.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import gmic 3 | 4 | """ 5 | This is a first example of using the gmic-blender 0.7+ addon for Blender 2.8x 6 | It was showcased at the Libre Graphics Meeting 2020 7 | 8 | Open or paste this script Blender 2.8x within the Text editor window 9 | and run it with Alt+P to let a little menu pop-up under your mouse. 10 | It will alter your last Render result (or may raise an error if no 11 | render has been done yet. 12 | """ 13 | 14 | class GmicEngraveOperator(bpy.types.Operator): 15 | bl_idname = "object.gmic_engrave_render" 16 | bl_label = "Gmic Engrave Render" 17 | 18 | def execute(self, context): 19 | #bpy.ops.render.render() 20 | bpy.data.images['Render Result'].save_render("somefile.tga") 21 | 22 | gmic.run("somefile.tga fx_engrave 0.5,50,0,8,40,0,0,0,10,1,0,0,0,1,0 display") 23 | 24 | return {'FINISHED'} 25 | 26 | class GmicDericheOperator(bpy.types.Operator): 27 | bl_idname = "object.gmic_deriche_render" 28 | bl_label = "Gmic Deriche Render" 29 | 30 | def execute(self, context): 31 | #bpy.ops.render.render() 32 | bpy.data.images['Render Result'].save_render("somefile.tga") 33 | 34 | gmic.run("somefile.tga deriche 3,1,x display") 35 | 36 | return {'FINISHED'} 37 | 38 | class GmicBlurOperator(bpy.types.Operator): 39 | bl_idname = "object.gmic_blur_render" 40 | bl_label = "Gmic Blur Render" 41 | 42 | def execute(self, context): 43 | #bpy.ops.render.render() 44 | bpy.data.images['Render Result'].save_render("somefile.tga") 45 | 46 | gmic.run("somefile.tga blur 3 display") 47 | 48 | return {'FINISHED'} 49 | 50 | class GmicDefaultRenderOperator(bpy.types.Operator): 51 | bl_idname = "object.gmic_default_render" 52 | bl_label = "Gmic Show Default Render" 53 | 54 | def execute(self, context): 55 | #bpy.ops.render.render() 56 | bpy.data.images['Render Result'].save_render("somefile.tga") 57 | 58 | gmic.run("somefile.tga display") 59 | 60 | return {'FINISHED'} 61 | 62 | 63 | class SimpleCustomMenu(bpy.types.Menu): 64 | bl_label = "G'MIC Quick Filters" 65 | bl_idname = "OBJECT_simple_custom_menu" 66 | 67 | def draw(self, context): 68 | layout = self.layout 69 | 70 | op = layout.operator(GmicDefaultRenderOperator.bl_idname, text = 'Default Render', icon='HAND' ) 71 | op = layout.operator(GmicBlurOperator.bl_idname, text = 'Blur', icon='META_ELLIPSOID' ) 72 | op = layout.operator(GmicDericheOperator.bl_idname, text = 'Deriche', icon='MESH_CUBE' ) 73 | op = layout.operator(GmicEngraveOperator.bl_idname, text = 'Engrave', icon='LIGHT_POINT' ) 74 | 75 | def register(): 76 | bpy.utils.register_class(GmicDefaultRenderOperator) 77 | bpy.utils.register_class(GmicBlurOperator) 78 | bpy.utils.register_class(GmicDericheOperator) 79 | bpy.utils.register_class(GmicEngraveOperator) 80 | bpy.utils.register_class(SimpleCustomMenu) 81 | 82 | def unregister(): 83 | bpy.utils.unregister_class(GmicDefaultRenderOperator) 84 | bpy.utils.unregister_class(GmicBlurOperator) 85 | bpy.utils.register_class(GmicDericheOperator) 86 | bpy.utils.register_class(GmicEngraveOperator) 87 | bpy.utils.unregister_class(SimpleCustomMenu) 88 | 89 | if __name__ == "__main__": 90 | register() 91 | 92 | # The menu can also be called from scripts 93 | bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname) 94 | -------------------------------------------------------------------------------- /examples/gmic-filters-default-parameters-to-operators/README.md: -------------------------------------------------------------------------------- 1 | Those scripts are not production quality, but I wanted them to be stored in 2 | some safe place in order to reuse their good parts some day when needed. 3 | The latest script in the list below (`bpy_operators_scripts.py`) was showcased at the LGM 2020 within the G'MIC+Blender presentation in the last Blender demo chapter. 4 | 5 | `default_parameters_gmic_py.py` was created from https://gmic.eu/filters290.json 6 | in some obscure way, maybe using this bash command: `cat /tmp/fff | cut -d' ' -f5,6 | sed "s/[^ ][^ ]*/'&'/g" | sed 's/ /: /g' | paste -s --delimiters="," > default_parameters_gmic_py.py` 7 | 8 | `make_operators.py` is a blender python script generator create 1 Operator class per G'MIC filters calling the latter's default parameters (tentatively..) 9 | 10 | `bpy_operators_scripts.py` is the resulting file, a generated python script for Blender 2.8x that can be run within Blender's Text editor with `Alt+P` 11 | -------------------------------------------------------------------------------- /examples/gmic-filters-default-parameters-to-operators/default_parameters_gmic_py.py: -------------------------------------------------------------------------------- 1 | default_parameters = {'afre_edge': '1,1,1,1','fx_gmicky': '0','afre_contrastfft': '75,50,1','fx_hnorm': '1,50,0','-srand': '781123','afre_gleam': '3,50','afre_vigrect': '50,75,10,50,50','afre_softlight': '100,0','afre_vigcirc': '90,75,50,50','mc_rooster': '50,0,255,255,255,255,1','mc_kookaburra': '50,0,255,255,255,255,1','mc_paw': '50,0,255,255,255,255,1','fx_array_mirror': '1,0,0,2,0,0,0','fx_array_fade': '2,2,0,0,80,90,0,0','Annular_Steiner_Chain_Round_Tile': '800,1,0,0,100,0,100,12,0,1,0,0,0,255,0,255,255,0,127,0,0,255,127,0','Cercles_Concentriques_A': '800,1,6,0,0,90,1,1,50,1,1,0,0,0,255,0,0,0,0,5,0,0,0,255,255,255,255,0,255,255,0,0,255,0,255,255,255,255,0,255,255,0,1,0,5,0,0','fx_imagegrid': '10,10','fx_array': '2,2,0,0,0,0','array_random': '5,5,7,7','fx_ministeck': '8,64,8,2,100,0.3,0','samj_Carres_Noirs': '128,40,7,0,0,0,0,255,2,96,96,96,255,2,255,255,255,255,0,2,0','Cercles_Concentriques_A_en': '800,1,6,0,0,90,1,1,50,1,1,0,0,0,255,0,0,0,0,5,0,0,0,255,255,255,255,0,255,255,0,0,255,0,255,255,255,255,0,255,255,0,1,0,5,0,0','fx_dices': '2,24,1','samj_Moirage_Spline': '0,0,0,255,8,0,-50,50,-50,50,0,0,0,0,0,255,8,0,-50,50,-50,50,0,0','samj_en_Coeurs_Hearts_002': '16,100,0,0,1,0,255,255,255,255,0,0,0,1,1','fx_imagegrid_triangular': '10,18,0,255,255,255,128','fx_taquin': '7,7,0,50,5,0,0,0,0,255,0','samj_Bulles_Colorees': '64,64,64,255,8,0,0,3,0,0,0,0,0,0,0,0,255','fx_puzzle': '5,5,0.5,0,0,0.3,100,0.2,255,100,0,0,0,0,0,0','fx_rotate_tiles': '5,5,15,3,3,1.8','samj_Ellipses_Colorees': '64,64,64,255,8,8,0,0,0,0,0,255','samj_Losanges_Colores': '64,64,64,255,8,0,0,0,1.5,0,1,0,0,0,0,0,255,0','fx_brushify': '7,0.25,4,64,25,12,0,2,4,0.2,0.5,30,1,1,1,5,0,0.2,1','samj_Contour_Drawings_en': '5,0,2,0,0,5,10,0.8,0,1.1,10,0,1','samj_Pixelisation_Contours': '0.5,0,20,8,0,0,1,0,10,0.8','samj_Pointes_De_Diamants_Colorees': '64,64,64,255,8,0,0,1.5,0,0,0,0,0,0,0,255,0','gtutor_fpaint': '0.5,0.5,0.0,0,45.0,0.5,0.5,0.5,0','fx_parameterize_tiles': '10,10,0','fx_shift_tiles': '10,10,10,1','fx_graphic_boost4': '1.25,2,0,0.15,14,0,1,0.5,0.45,2,0,1,0,1,1,1,0.5,0.45,1','gcd_aurora': '6,1,0','fx_crayongraffiti2': '300,50,1,0.4,12,1,2,2,0','fx_cpencil': '1.3,50,20,2,2,1,0','Engrave_colore_en': '0,0.5,4,0,8,40,0,25,1,2,0,0,0,255,255,255','fx_neon_alpha': '0,0.45,40,60,0,2,1.15,20,0.4,0.1,2.25,5,0.2,0.1,2.25,2,1','afre_sharpenfft': '15,1','fx_tk_photoillustration': '0,0.25,0,0.30,0.50,0.50,1.00,0,5.00,0,1,0,0,1,0,0,1.2,98.5,5,0.5,0,0,0,0,0,1,0','fx_dreamy_watercolour': '0,0.3,40,60,0,1,50,0,10,2,1,1,0.5,10,0,0,7,1,3,1,1,1,1,1,11,1,25,5,1,10,1,0,0,1,0.5,0,8,1,0,128,128,128,0.5,1,8,0.2,1,1,0,27,0.75,0,1,20,40,40,1,2,1.25,0,2,1,27,1','samj_Edges_And_LIC': '0,200,0,0,0,15,8,127,255,0,0,1,20,0.2,0,14,1','samj_Angoisse': '1,5,0,5,100,2,4,1,250','mc_dragonfly': '50,0,255,255,255,255,1','fractalize': '0.8','samj_Couleurs_Rayees': '0,30,0,100,4,4,0,2,0.7,0','samj_en_Texture_Granuleuse': '0,20,80.0,0,0,0','Annular_Steiner_Chain_Round_Tile_en': '800,1,0,0,100,0,100,12,0,1,0,0,0,255,0,255,255,0,127,0,0,255,127,0','samj_Fond_Brosse': '3,1','fx_illustration_look': '100,0,0,0,0','fx_MorphoPaint': '1,18,2,25,100,230,8,3,4,0.5,2,0.5,200,1,1,1,1,1,1,1,1,0','fx_array_color': '5,5,0.5','samj_Isophotes_Vers_Aquarelle': '16,0.5,4,0,1,10,1,0,0,0,0,1,10,10,4,3,251,237,206,1','fx_pastell': '0.6,1,0,20,30,300,1,30,1,1,0.5,0,0,10,3,0,9,3,0,12,0','samj_Barbouillage_Paint_Daub_en': '2,2,100,0.2,1,4,1,0,8','fx_SimpleNoiseCanvas': '0,3,2,5,5,0,255,0,2,0,0,0,1,0,255,255,255,255,0','samj_Scintillements_Colores_en': '64,64,64,255,8,8,0.5,384,12,0,0,0,0,0,0,0,255,0','warhol': '3,3,2,40','samj_Plasmic_V2': '2,4,10,2,0.02,8,0,0,0,0,0,0,255','fx_pdithered': '1,1,0,0,20,1,0,1,0','fx_imagegrid_hexagonal': '32,0.1,1','fx_autofill_lineart': '90,1,8,0,0','Engrave_colore': '0,0.5,4,0,8,40,0,25,1,2,0,0,0,255,255,255','samj_Contour_Epais': '1,0,5,1,5,5,10,0.8,2,1','samj_Color_EdgesO_Engrave': '0,50,9,1,2,50,0,8,40,0,0,1,0,0,0','fx_montage': '0,"V(H(0",1,0.5,0,0,0,0,0,255,0,0,0,0,0','fx_gcd_layeretch': '11,4,12,0.12,100,8.5,5,0,0,3,1,1,0','samj_fond_broderie': '8,2,0,1,1','samj_Diff_Tensors_Blend': '10,5,1,0.15,1,0,3,1,0,3,1','samj_Coeurs_Hearts_002': '16,100,0,0,1,0,255,255,255,255,0,0,0,1,1','fx_channels2layers': '0','samj_Impressions': '10,5,5,1,1,0,2,0,1,5,0,5,100,2,4,1,250,1.2','samj_Gris_Raye': '0,30,0,100,4,4,255,1','samj_Moirage_Spline_XY': '0,0,0,255,8,0,-50,50,-50,50,0,0,0,0,255,8,0,-50,50,-50,50,0,0','fx_tk_colortemp': '0,0,0','samj_texture_coloree': '"A",0.7,200,125,50,5,5,45,200,4,0.2','samj_TensorTest': '0.3,0.9,0.6,1.1,0,0,20,32,20,2,1,0,2','fx_normalize_tiles': '25,25,0,255,11','fx_hsv_equalizer': '0,180,40,0,0,0,180,40,0,0,0,180,40,0,0,0','-srand': '781123','samj_texture_coloree_en': '"A",0.7,200,125,50,5,5,45,200,4,0.2,1,10,1,1','iain_hue_light_dark_p': '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,100,255,0,0,0','samj_Angoisse_en': '1,5,0,5,100,2,4,1,250','fx_whirling_lines': '30,6,0,0,0.45,40,60,0,0,30,0,3,3','fx_recolorize': '2,0.2,0','samj_Variations_RVB': '50,50,0,6,0,0,180,90,45,0,1,0','fx_ColorAbstractionPaint': '5,10,1,0,1,0,1,0,0,0,0,0,0,0','fx_colorize_lineart_smart': '0,95,0,0,1,24,200,0,75,2,60,20,90,1,10,1,0','fx_gcd_norm_eq': '0.5,0.5,2,0','fx_tk_vintage': '2,0.85,0.7,80,200,5,147,26,161,0.3,235,220,176,0.4,190,181,108,0.2,0,0,100,0,0.3,25,0,0','fx_dreamsmooth': '3,1,1,0.8,0,0.8,1,24,0','XY_hardsketchbw_samj_en': '0.2,300,50,1,0.1,20,0,0,0,0,180,40,160,255,0','fx_ink_wash': '0.14,23,0,0.5,0.54,2.25,0,2,6,5,20','samj_Coloriage': '612,255,2,6,2,0,0,0,255,0','samj_Flamboyance_Test': '65,28,9.25,0.3,0,1,1.1,10,12,2,0,0,1,0,150,0.42,0.85,0.6,7.83,0.68,19,2.65,0,1,1,3,200,20,0.1,1.5,8,1,3,1,0,20,0,0,0,0','fx_remove_scratches': '72,2,4,3,0','samj_scintillements': '0,5,0,1,20,2,6,20,5,45,2,6,5,20,1,7,0,0','fx_graphic_novelfxl': '0,2,6,5,20,0,0.62,14,0,1,0.5,0.78,1.92,0,0,0,1,1,1,0.5,0.8,1.28','samj_Quelques_Isophotes_B': '16,100,0,0,4','samj_Color_Palettes': '50,50,0,6,24,0,0,180,90,45,1,3,2,1','jl_colorgrading': '0.,0,1,1,0,0,0,0,0,0,1,0,0,0,70,0,0,0,0,0,70,180,0,1,0,0,0','fx_otsu_hessian_blend': '4,0,1,27,1,0','fx_corvo_painting_5': '35,10,10,0.5,50,0.3,50,2,5,1','fx_darken_sky': '.75,5,0,1,0,0','fx_decompose_channels': '7,0,0,1','samj_Plasmic': '0,1.1,2,40,0,0,0,0','fx_conformal_maps': '8,1,0,1,0,0,0,0,0,3,0,0,1024,1024','gcd_hsv_select': '0,0.5,1,180,0.5,0.5,2,2,18,0,0,0','gcd_hsl': '1,0,0,180,0.2,0,1,1,0','samj_Barbouillage_Paint_Daub': '2,2,100,0.2,1,4,1,0,8','fx_equirectangular2nadirzenith': '0','iain_rgb_tone': '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0','samj_At06A_2017_VarCouleurs': '1,0,100,0,0','samj_Couleurs_Rayees_2': '0,30,0,100,4,4,255,1','samj_Random_Small_Deformations': '10,5,3','iain_tone_presets_p': '0,100,0,0','fx_gcd_transfer_colors_patch': '6,3,5,5,0,0','samj_fx_sketchbw_modifie': '3,45,180,30,1.75,0.02,0.5,0.75,0.1,0.7,3,6,0,1,4,0,1234,0,2,100,0.2,1,4,1,0','fx_reflect': '50,1,110,160,190,64,0,1.5,0,-3.30,7,1.5','samj_Colored_Outlines': '0,2,8,0,0,0,0,0,255','samj_Carte_De_Repoussage': '30,1,0,0','samj_Pointillisme_B': '1,0,90,3,1,1,0,0,0,255','ripple': '10,20,2,0,0','samj_Quelques_Isophotes': '10,10,1,0.02,8','samj_Contours_Colores': '1.1,2,40,0,0','samj_Test_Skeletik': '10,1,0,0,0,3,1,0,0,0,255','samj_Cercle_Polaire': '1,0,0,1,0,0,2,0,0,0,50,50','samj_Skeletation': '2,100,100,0,0,1','samj_Test_Mauvais_Contours': '0,0,0,2,1,0,255,0,255,0,0,3,1','fx_watercolor': '1.8,0.1,1,80,0,0.5,0,0,0,2,0,2,4,2,0,3,3,2,0,4,2,0,0,0,0,0','fx_seamcarve': '85,100,15,0,1','fx_apply_YCbCrcurve': '0,-1,128,-1,128,-1,128,-1,128,-1,128,255,1,0,0','fx_auto_gnarl': '3,0.45,40,60,0,1,1,2,4,6,5,20,1,2.5,0.5,2,2,3','fx_colorize_lineart': '0,1,0,0.05','fx_map_sphere': '512,512,90,0.5,0,0,20,0,0,0,0.5','fx_crease': '30,10,3','fx_drop_water': '0,20,2,80,0,3,35,10,1,0.5,0.25,0.5,0.75,0.05,0.15,1','engrave_modifie': '0,0.5,4,0,8,40,0,25,1','fx_jr_spiral_transform': '0,0,0,0,0','raindrops': '80,0.1,1,0','deform': '10','samj_NB_EdgesO_Engrave': '0,50,9,1,2,50,0,8,40,0,0,1','fx_square_circle': '0,1,0,0,0,0,0','sawtoother_yuv8': '1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,0,2,0','fx_yag_soften': '0,0,0','iain_cmyk_tone_p': '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0','water': '30,1.5,45','fx_frame_blur': '30,30,0,5,0,0,128,128,128,0,5,255,255,255,2,2,1,0,0.5,0.5,0','fx_jr_smooth_eq': '8,2,0,3,2,1.5,0,4,2,2,0,5,2,2,0,6,2,2,0,7,2,2,0,3,2,0,0,0,1,1,0','fx_customize_clut': '100,0,10,0,0,0,0,0,0,0,8,0.5,1,0,0,0,0,0,0,1,255,255,255,255,196,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0','fx_simulate_grain': '0,1,0.2,100,0,0,0,0,0,0,0,0','frame_cube': '3,0,0,0,0,0,0','fx_streak': '255,0,0,255,0,0,3','fx_frequency_representation': '3,256,0,40,0','fx_blur_bloom_glare': '1,2,5,0,0,0,0,0,3,0.5,7,0','fx_superstreak': '10,10,3,0.50,0.50,10,30','fx_tk_metallic': '1,0,0,0','fx_frame_fuzzy': '5,5,10,1,255,255,255,255','fx_butterworth_bp': '3,2,0,4,2,0,0,0,1,1,0','fx_watermark_visible': '"\251','Saturation_EQ_p': '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0','fx_frame_mirror': '10,10,50,50,0,0,0,0,0.75','fx_gcd_crt': '1.8,1.8,0,0','fx_morpho': '0,5,0,0,0,0,0','fx_frame_painting': '10,0.4,6,225,200,120,2,400,50,10,1,0.5,123456,0','fx_zonesystem': '1,10,1,1,0,255,0','samj_Zones_Grises_en': '3,0,3,4,1','fx_bitplane8': '0,1,0,0','fx_frame_pattern': '10,1,1,1','samj_Contours_Arrondis': '1,3,5,10,0,0','fx_jfif_xt': '50,8,8','iain_constrained_sharpen': '.75,2,1,5,0,11,1','fx_frame': '0,100,0,100,10,10,0,0,0,255,1,255,255,255,255','samj_Scintillements_Colores_Contours': '0,8,0,8,8,1,768,12,0,0,0,0,0,0,0,255','samj_Degradations_Path_Solidify': '0,0,0,0,0,2,10,1,0,0,1,75,0,20','jeje_dehaze': '5,1,.2,1,0,0,0,0,0','fx_frame_round': '6,20,0.1,0,255,255,255,255,0,0.1,3','fx_apply_Labcurve': '0,-1,128,-1,128,-1,128,-1,128,-1,128,255,1,0,0','fx_pixelsort': '1,0,0,1,0,100,0,0,0','fx_tk_dri': '0,0,0,1,0.5,1,1,0','souphead_droste10': '40,100,1,1,1,0,0,0,0,0,1,10,1,0,90,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0','fx_frame_smooth': '10,10,0.25','samj_Random_Plasma': '0,80','fx_highpass': '5,2,0,0,0','fx_symmetrizoscope': '4,0,3,0','fx_old_photo': '200,50,85','fx_row_shift': '0,0,0.5,0,0.5,3,0','fx_LCE': '80,0.5,1,1,0,0','gcd_jpeg_smooth': '1,1,0,0','fx_polaroid': '10,20,0,0,3,0,20,50,70,95','samj_Ellipses_Inpaint': '0,0,0,8,8,2,0,10','jeje_normalize_local_variance': '50,5,5,1,0,0','gcd_layers': '100,0,1,0,0,0,0,0,1,0,0,1','samj_At06A_2017_frame_painting': '10,0.4,6,127,127,127,2,400,50,10,1,0.5,123456,35,1,1,1,0,100','samj_Zones_Grises': '3,0,3,4,1','make_up': '15,4,0,0,0','gcd_balance_lms': '1,1,1,0,0,0','fx_vignette': '70,70,95,0,0,0,255','sawtoother_cmy_k': '1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,0,1,0,0,1,1,0,0,2,0','fx_tk_mask': '0,0,0,255,0,1,0,0,1,0','gcd_fx_local_fmean': '15,0,0,5,0','fx_fourier': '1,1','sawtoother_hsx': '1,0,0,1,1,0,1,0,0,1,1,0,0,1,0,0,1,1,0,0,2,0','fx_tk_portrait': '0,100,1,5,20,3,20,10,0,0,1,2,25,2,250,180,150,255,0,0,1,1.5,10,1,0,0,1,1,0,0','fx_watermark_fourier': '"(c)','tran_multi_threshold': '50,100,150,200,9,0,1,175,42,27,101,101,101,174,165,131,247,228,160','sawtoother_lab8': '1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,0,2,0','iain_pyramid_processing': '4,50,.5,0,0','gcd_normalize_brightness': '0,10,0,3,0,0','gcd_anti_alias': '60,0.3,50,0','sawtoother_lch8': '1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,0,2,0','samj_Antialias_Wavelet': '40,0,127,255,1,60,1,1,1','fx_gcd_quicktone': '1,4,20,0,3,1','gcd_auto_balance': '30,0,0,1,0','sawtoother_rgb': '1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,0,2,0','jeje_hessian_sharpen': '3,1,1,0,0','gcd_recol': '-14,14','gcd_blend_feather': '100,0.5,2,0,0','sawtoother_srgb': '1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,0,2,0','samj_Wavelet_Sharpen_Test_en': '0,0','gcd_sharpen_gradient': '0.5,2,0,0','gcd_comp_blur': '2,3,1,100,1,0,0','sawtoother_xyz8': '1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,0,2,0','jeje_whiten_frequency': '50,0,0','gcd_sharpen_tones': '1,128,0,0','fx_gcd_cumul_math': '0,1,1,0,0','sawtoother_ycbcr': '0,1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,0,2,0','fx_split_details_alpha': '6,10,1,5,0','gcd_srotate': '0,50,50,1,1,6,0.6,0','gcd_depth_blur': '0,15,0.25,2,4,0,1','sawtoother_yiq8': '1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,0,2,0','fx_split_details_gaussian': '6,10,1,0','gcd_emboss': '128,0','gcd_temp_balance': '0,0,1,0','iain_easy_skin_retouch': '7,2,.7,1,1,.7,.6,.5,.5,.5,0','fx_split_details_wavelets': '6,0,0','gcd_geometric_balance': '0','gcd_unquantize': '6,1,1,5,15','exfuse': '1,0.6,0,0.5,1,5','jeje_spotify': '1,1,1,1,11,0','gcd_upscale_box': '0,0,0','gcd_infomap': '0','exfusion5': '0,.2,0.2,1,0,0','iain_texture_enhance_p': '2,2,30,0,11,0,0','gcd_ebwarp': '0.5,1','gcd_upscale_noise': '16,2','fft_tile': '500,128,0','gcd_tone_enhance': '0,1,0,1,128,0,1,0.5,0,0,4,0,0','gcd_warpmap': '5,0,0,0,0','MS_Patch_NR3': '1.3,0,0,0,3,5,1,0,0,0,0,0','fill_holes': '11,21,5,0,0,1','samj_Wavelet_Sharpen_Test': '1','fx_gb_cfx': '10,0,0,0,0,0','ms_patch_smooth': '10,5,3,5,0,1,1,7,5,4,3,2,1,1,1.3,0','iain_descreen2': '3,-10000,10','jpr_phasecongruence': '45,1,50,1','fx_gb_lb': '10,7,0','ms_smooth': '0,0,0,0,0,0,2,0,2,0','iain_halftone_shapes': '100,0,0,0,0,0,0','hedcut': '0.5,0.5,0.5,0.0,0.5,0,1,0','jpr_remove_blocks1': '4,3,70','nr5': '1.6,5,1,1,.75,3,0,.75,.5,0,1,1,100,0,-100,0,1.3,0','iain_hearttone': '100,0','jpr_shapes_gradient': '2,0.25,0.001,100','iain_png_processing': '4,0,0,0,3,3,0,.75,2,1,5,0,0,1,1','iain_2d_scopes': '1,2,2,6,512,2048,1,0,0,0,0','iain_demosiac': '0','jpr_specularbumps': '270,1,13,0,80,0.1,0.1,0','iain_smooth_tutorial': '1000,0.5,1,0.6,1.1,0,0','simplelocalcontrast_p': '16,2,0,1,1,1,1,1,1,1,1,0','iain_denoise_2019_beta3': '1,0,0,0,0.5,1,0,5,3,0,3,0,.5,4,0','jpr_warpfromthreshold': '170,2,10,2','automixer': '0,0','iain_fx_skin_mask': '55,200,0,0,0,1','iain_remove_pattern': '3,3,3,0,4,128,1,0','fx_mesh_blend': '0,3,0,0,0,0','iain_brown_spot_clean': '1,2','iain_smartdemos': '0,1.5,2','iain_star_burst': '254,50,5,45,2,0,0','iain_CA_correction': '0,0,2,0,3','fx_align_layers': '0,0.7,0,0','star_tone': '100','iain_detect_moire': '50,5,9,30','iain_unindex': '30,20,1,50,50','fx_blend_average_all': '0','iain_sub_cast': '5,20,250','fx_tones2layers': '3,85,170,0.5,0','iain_weightmap': '1,40','fx_blend_edges': '1,0.8,0','iain_turbulent_halftone': '15,20,0,1,512,0.75,0,0,0','fx_contrast_swm': '2,0,1','iain_iains_nr': '3,3,1,0,0,0,1,0,0,0,1.35,0,0','fx_blend_fade': '1,0,0,5,0,0,0,0,0,0,"cos(4*pi*x/w)','mc_flip': '50,0,255,255,255,255,1','fx_dodgeburn': '15,1.5,25,10,40,1.5,25,10,0,0,10,0','iain_iid_demosaic': '1,1,1,0,0','fx_blend_median': '0','mc_information': '50,0,255,255,255,255,1','fx_drop_shadow': '3,3,1.8,0,0,0','fx_blend_seamless': '0,0,25,0,0','luminance_nr_two': '10,1,1,.8,.7,.6,.5,.4,.3,1200,64,0,0,0,0,0,0,0,0,0,0,0','mc_mail': '50,0,255,255,255,255,1','fx_drop_shadow3d': '0,0,0,0,1,1,2,0.5,0,0,0,200,0','mc_phone': '50,0,255,255,255,255,1','iain_minimum_chroma_demosaic': '0,2,0','fx_blend': '6,0,100,1,"1/2','fx_light_patch': '5,0.7,2.5,0','mc_shopping_cart': '50,0,255,255,255,255,1','iain_moire_removal': '5,5,0','fx_split_colors': '50,16,1,0','samj_Ombre_Portee': '0,0,0,128,0,0,0,0,255,127,127,127,255,2,2,255,255,255,255,0.1','iain_moire_removal_NP': '5,5,0','jeje_zernike_preview': '50,50,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0','fx_fade_layers': '10','samj_Ombre_Portee_B': '16,128,0,1,16,1,0,0,127,127,127,255,2,2,2,2,255,255,255,255','ms_nlmeans_c_noise2_p': '3,1,0,0,0,0,0,10,2,4,2,7,0,0,0,0','append_tiles': '0,0','jpr_colourillusion': '2,25','samj_Ombre_Portee_C': '32,8,16,192,0,1,16,1,0,0,96,96,96,255,2,2,2,2,255,255,255,255','fx_morph_layers': '10,0.2,0.1,0','jpr_coltexindex': '5,55,55,45,45,1,1,0,0.05,0.5,0.95,0.5,1,2,0.7','ms_patch_c': '5,1,1,5,4,3,2,1,1,1.3,0.375,.5,0.125,0','samj_Ombre_Portee_D': '16,64,64,2,1,16,5,1,-32,4,1,2,2,2,255,255,255,255','fx_apply_multiscale': '4,25,100,0,3,0.5,0.5,0,0,0.5,0.5,0,"",0,0','MS_Patch_NR': '1.3,0,0,0,3,5','jpr_decimate': '0.375,2','fx_shadow_patch': '0.7,0','Lylejk_Wicker_2': '50,50,1,50,50,1,1,12,10,5,1,1,0,0,0,255,150,0.54,0.85,0.6,7.83,0.68,19,2.64,0,1,3,0,0.29,28.7,100,0,0,1,10,20,0.1,1,10,12,2,40,0.7,0.3,0.6,1.1,0.8,30,2,0,1,3,1,0,16,1,0','fx_stroke': '3,50,0,2,1,100,0,0,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,1,0','jpr_gradient_smooth': '0,1.5','fx_slice_luminosity': '1,1,2,1,0,64,0,0,1,64,128,0,0,0,128,192,0,0,0,192,255,0,0','Lylejk_Woven': '19.6,32.4,1,0,0,19.6,32.4,1,0,0,12,10,5,1,1,0,0,0,255,19.6,32.4,1,0,0,19.6,32.4,1,0,0,150,0.61,0.85,0.6,7.83,0.68,19,2.64,0,1,1,0,0.29,37.2,100,0,0,2,0,16,0','split_tiles': '3,3,0','jpr_orientedthinning': '5,15,1,0,0','fx_blend_shapeaverage': '1,0,0','fx_split_luminance': '1,1,1,0,0','garagecoder_lylejk_samj_points_outlines': '0,0.05,10,0.12,0,0,2,0','fx_crystal_background': '10,25,0,100,1','fx_lylejk_stencil': '5,10,3,0','fx_hue_overlay_masks': '0,5','fx_MappedSmooth': '0,0,0,300,1,0','samj_Degrades_HSL_TSL': '4,800,240,240,40,255,120,40,240,255,0,0,0,360,100,100,0,0,0,718,75,100,0,100,0,0,0,0','Lylejk_Luma_Invert': '1,0','fx_fix_HDR_black': '20,25,50,200,0,0','mc_barbed_wire': '50,0,255,255,255,255,1','jeje_fibers': '10,50,10,0','Lylejk_Quantize_Wicker': '16,50,50,0,16,10,5,1,1,0,0,0,255,1,10,10,153,0,2,10,20,0.1,1,0','fx_noisepainting': '0,0,0,5,2.5,1.5,50,1,0','mc_crosshair': '50,0,255,255,255,255,1','samj_Formes_Couleurs_Variees_Dans_Image': '0,0,0,0,0,192,128,64,255,1,1,1,0,0,127,255,0,0,0,0,1','Lylejk_Ribbon': '150,0.42,0.85,0.6,7.83,0.68,19,2.64,0,1,2,16,3.44,0,3,0.79,0.72,4.97,1.70,150,0.42,0.85,0.6,7.83,0.68,19,2.64,0,1,2,0,0.32,43.1,100,0,2,1.15,5,1,0','fx_SmoothSketch': '1,6,0.8,0.3,0.3,0,1000,0,50,10,2,0.6,0.55,1,0','fx_cupid': '75,0,255,255,255,255,1','fx_marble': '.5,1,0,0,.4,.6,.6,1.1,0,100','lylejk_test_TRW': '50,50,1,16,10,5,1,1,0,0,0,255,50,50,1,1,1.8,10,153,150,0.42,0.85,0.6,7.83,0.68,19,2.64,0,1,1,0,0.5,10.5,100,0,0,0.5,10.5,100,0,1.15,5,1,0.68,0.5,10.5,100,0,0,1,10,1,0,0','fx_gear': '75,12,15,0,40,0,255,255,255,255,1','fx_DemoVecRot': '0','samj_Marbre_en': '1,1,8,5,0.2,0,0,0,140,120,220,0,3,1','Lylejk_Wicker': '10,10,153,150,0.42,0.85,0.6,7.83,0.68,19,2.64,0,1,1,0,0.5,10.5,100,0,0,0.5,10.5,100,0,1.15,5,1,0.68,0.5,10.5,100,0,0,1,10,1,0,0','fx_WarpTest': '0,0,0,1,0','fx_heart': '75,0,255,255,255,255,1','fx_maze': '24,1,0,1,0','jeje_rays': '50,50,10,0,0.5,255,0,0,255,255,0,0','mc_paint_splat': '50,0,255,255,255,255,1','mc_australia': '50,0,255,255,255,255,1','fx_mineral_mosaic': '1,2,1,100,0','samj_Rays_Of_Colors': '300,12,40,16,38,1,0,0,0','fx_barnsley_fern': '0,100,30,40,10,178,0,255,1','fx_sierpinski': '6,50,0,0,100,100,100,255,255,255,1','samj_Motifs_Aleatoires_Symetriques_Degrades': '0,400,4,1,1,1','samj_Contours_Gros_Pixels': '1,8,0,20,20,16,1.1,0,0,15,0,0,0,1','fx_AbstractFlood': '1,10,7,2,0,10,5,3,255,255,255,255,0,300,10,90,0.7,0,0,0','samj_Degrades_XYZ_CIE': '6,800,240,240,40,255,120,40,240,255,0,0,0,100,64,64,0,0,1,0,100,-128,128,-128,128,0,11,0,0','samj_EPPE_Transform': '50,50,0,10,10,32,0.1,10,18,0,255,255,255,255,3,0,0.1','fx_bwfilmsimulate': '0,0.299,0,0.587,0,0.114,0,1,1,0,0,0,0,0,0,2,0,0,0,16,4,0','samj_Lignes_H_ou_V_Colorees': '159,190,195,55,67,140,54,40,39,140,81,88,207,175,190,220,202,196,170,186,192,130,149,139,112,96,96,237,168,138,220,199,205,234,217,219,255,256,256,1,0,0','mc_gum_leaf': '50,0,255,255,255,255,1','fx_blockism': '3,1.6,0.5,50,0.5,64,0,1,0','samj_Marbre': '1,1,8,5,0.2,0,0,0,140,120,220,0,3,1','fx_CompositionAnalysis': '0','samj_Motif_Plasma': '2,20,20,30,1,75,0','fx_shapes': '1,16,10,2,5,90,0,0,1,1,0','fx_dodgesketch': '3,10,7,2,0,0','mc_maple_leaf': '50,0,255,255,255,255,1','samj_Motifs_7200': '2,0,20,20,30,1,75,0,0,255,0,221,255,0,0,0','fx_ExposureWeightMap': '0.3,0.3,0.2,0.3,1,0','samj_Motifs_7200_VarianteA': '2,0,20,20,30,1,75,0,0,255,0,221,255,0,0,0','samj_Steps_V2': '10,10,4,1,10,2,60,0,1.1,10','samj_Tissu_Fond_Flou': '0,0,100,100,0,1,0,1,0,0,0,0,0','fx_snowflake': '5,1,255,255,255','samj_Variation_Stained_Glass': '0,2,8,0,3,40,100,0,1.1,20','jeje_periodic_dots': '6,4,0,1,0','fx_satin': '20,1,0,0,0,0,255,255,255,255,255,0,0,0,-50,0,0','fx_mad_rorscharchp': '3,0,50,1,300,0,0,0,0','fx_jobs_colors': '0,0,0','fx_StructureTensors': '0.1,0','fx_plaid_texture': '50,2,0,90,1,300','fx_stars': '10,0,32,5,0.38,0,255,255,100,200','samj_en_Contours_Gros_Pixels': '1,8,2,20,20,16,1.1,0,1,15,1,0,0,1','fx_dragoncurve': '20,0,1,255,255,255','jeje_strip': '45,50,0,1,0','samj_Points_Aleatoires_001': '10,255,255,0,255,3,0,1','fx_tetris': '10','rgb2bayer': '0,1','fx_truchet': '32,5,1,1,0','fx_camouflage': '9,12,100,30,46,33,75,90,65,179,189,117,255,246,158','jeje_turing_pattern': '1,2000,.1,.899,-.91,2,.1,.25','fx_polka_dots': '80,20,50,50,0,0.5,0.1,1,255,0,0,255','weave': '6,65,0,0.5,0,0,0,0,0','texturize_canvas': '20,3,0.6','fx_color_ellipses': '400,8,0.1','fx_elevation3d': '100,1,1024,1024,0.8,25,0,21,45,0,0,-100,0.5,0.7,2,1','fx_steampen': '0.95,14,2,2,0.9,0,1,0,0.5,0.75,0.48,0','fx_extrude3d': '10,512,0.6,1024,1024,0.5,57,41,21,45,0,0,-100,0.5,0.7,4,1','fx_graphic_boost': '1.25,2,0,0.15,14,0,1,0.5,0.45,2,0,1,0,1,1,0.5,0.45,1,0','fx_compose_boostscreen': '0.7,0,0.7','fx_imageobject3d': '1,1024,1024,0.5,57,41,21,45,0,0,-100,0.5,0.7,4,1','fx_compose_colordoping': '1,0','fx_lathing3d': '76,2,361,1024,1024,0.5,0,0,0,45,0,0,-100,0.5,0.7,4,1','fx_colorstamp': '1,50,1,20,2,0','fx_random3d': '0,50,3,100,45,0,0,-100,0.5,0.7,3,1','fx_compose_graphicolor': '0.6,0,0.8','fx_compose_comix_color': '1,0,1','samj_Adjacent_Annular_Steiner_Chains_en': '50,50,0,0,6,56,20,50,0,255,0,221,127,72,0,255,127,0,145,255,127,0,255,144,127,72,255,0,127,255,217,0,127,255,0,0,127,5,0,0,2,0,0,0,255,0,0,0','fx_compose_darkedges': '1,0.5,0,0.7','samj_Adjacent_Annular_Steiner_Chains': '50,50,0,0,6,56,20,50,0,255,0,221,127,72,0,255,127,0,145,255,127,0,255,144,127,72,255,0,127,255,217,0,127,255,0,0,127,5,0,0,2,0,0,0,255,0,0,0','fx_novelfx': '0,2,6,5,20,0,0.62,14,0,1,0.5,0.78,1.92,0,0,0,1,1,0.5,0.8,1.28,0','samj_Rectangles_Adjacents': '10,10,80,80,0,50,6,0,0,0,0,0,255,1,255,255,0,127,0,0,255,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_en_Rectangles_Adjacents': '10,10,80,80,0,50,6,0,0,0,0,0,255,1,255,255,0,127,0,0,255,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_en_Annular_Steiner_Chains': '50,50,50,6,0,0,0,0,255,1,255,255,0,127,64,192,128,127,0,255,0,127,0,0,255,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_Annular_Steiner_Chains': '50,50,50,6,0,0,0,0,255,1,255,255,0,127,64,192,128,127,0,255,0,127,0,0,255,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','fx_compose_heavyscreen': '0.6,0,0.7','fx_phoenix': '0.95,14,2,2,0.9,0,0,0,1,1,0','fx_smooth_anisotropic': '60,0.16,0.63,0.6,2.35,0.8,30,2,0,1,1,0,1','fx_psyglass': '0,20,0.1,1,1,0,1,1,0,1,1,0,0,2,0,0,0','fx_viral': '3,0,0,0,0,0','fx_compose_vivid_color': '1,0,1','fx_compose_vividedges': '1,0.5,0,0.7','fx_seamless_turbulence': '15,20,0,1,3,0','samj_Noel_2016': '50,50,100,150,7,0,240,45,15,255,-15,2.5,2,0.8,1,1.5,0,0,0,0.25,10,0.8','fx_compose_vividscreen': '0.6,0,0.7','samj_Chryzodes': '100,0,0,0,255,0,50,50,45,79,3,1,240,128,64,255,0,0,0,0,0,0,0,0,0,0,0','fx_m_l_unsharp2': '12,2.18,0.3,1.5,1,0.5,0,0.5,0.8,1.28,0','samj_en_Chryzodes': '100,0,0,0,255,0,50,50,45,79,3,1,240,128,64,255,0,0,0,0,0,0,0,0,0,0,0','samj_Contour_Line_Laser_LED': '0,1,0','samj_dessiner_un_polygone': '5,50,50,0,40,50,1,255,255,0,0,0,0,0,1,0,0,255,0,0,255,0,0,0,127,127,127,0,0,0,0,0,255,255,255,0,0,0,0,1,255,0,0,0,1','samj_Egg_Oeuf_Granville': '50,50,0,20,30,10,0,0,0,0,255,1,255,255,0,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_Egg_Oeuf_Hugelschaffer': '50,50,50,6,48,0,0,0,0,0,255,1,255,255,0,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_Egg_Oeuf_Rosillo': '50,50,40,200,300,0,0,0,0,255,1,255,255,0,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_Engrenages_Laser_LED': '80,20,12,14,17,1,1,2,19,250,0,0,0,0','fx_equation_parametric': '"sin(t)*(exp(cos(t))-2*cos(4*t)-sin(t/12)^5)","cos(t)*(exp(cos(t))-2*cos(4*t)-sin(t/12)^5)",0,100,4096,1,0,64,0,0,128,0,0,1,1,1','fx_compose_darkscreen': '0.7,0,0.7','samj_Etoile_De_Pompei_Triangles_Sierpinski': '50,50,30,100,0,0,0,255,0,5,255,0,0,127,255,0,255,127,0,0,255,127,0,255,255,127,255,255,0,127,0,63,255,64,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_Etoiles_Laser_LED': '1400,5,2,0,0,0,0','samj_Etoiles_Remplies_Triangles_Sierpinski': '6,50,50,50,40,30,0,0,0,0,0,255,1,4,255,0,0,127,255,192,64,127,0,0,255,127,0,255,255,127,255,255,0,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_Flocon_De_Neige': '50,50,6,50,40,0,3,192,192,192,1,0,3,255,255,255,0.7,0,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_Flocon_Laser_LED': '1400,6,5,0','samj_Fractal_Tree': '50,100,-90,11,10,20,255,0,0,255,20,0,4,1,0,0.25,10,0.8,0','fx_corner_gradient': '255,255,255,128,255,0,0,255,0,255,0,255,0,0,255,255,1','fx_custom_gradient': '0,0,0,1,4,1,0,128,100,100,2,0,1,0,"",1,0,0,0,0,255,255,0,0,255,255,255,0,255,255,255,255,255,0,255,255,255,0,255,0,255,0,0,255,255,128,128,128,255,255,0,255,255,0,0,0,0','fx_linear_gradient': '0,0,0,255,255,255,255,255,0,45,0,100,0','fx_random_gradient': '32,0,0,128,128,128,1','fx_ball': '128,0.8,1,1.5,255,0,255','samj_Linear_Gradient_CIE_Lab': '0,0,240,40,160,255,240,240,40,255','samj_en_Shape_Linear_Gradient_CIE_Lab': '10,10,90,90,2,0,240,40,160,255,240,240,40,255,0,0,0,0,255,0','samj_Shape_Linear_Gradient_CIE_Lab': '10,10,90,90,2,0,240,40,160,255,240,240,40,255,0,0,0,0,255,0','gtutor_hairlock': '0.5,0.5,0.5,255,255,0,255,0.5,45,0.5,0.5,0','Harmonograph_samj_en': '50,50,192,128,64,255,0,0,1000,0,400,150,200,200,100,4,6,2,2,15,270,75,60,0.04,0.04,0.05,0.06,0,0,0,1,1','Harmonograph_samj': '50,50,192,128,64,255,0,0,1000,0,400,150,200,200,100,4,6,2,2,15,270,75,60,0.04,0.04,0.05,0.06,0,0,0,1,1','samj_Hawaiian_Earring': '50,50,40,6,0,0,0,0,0,255,1,255,255,0,127,0,0,255,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_en_Hawaiian_Earring': '50,50,40,6,0,0,0,0,0,255,1,255,255,0,127,0,0,255,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','Traits_Strokes_samj_en': '50,50,35,0,100,0,30,0,360,240,60,120,255,0,0,0,20,0,0,0,1,1','fx_coloredobject3d': '1,128,128,128,255,0.5,0.5,0.5,57,41,21,45,0,0,-100,0.5,0.7,4,1','samj_en_Lignes_Epaisseur_Variable': '0,32,3,0,0,0,255,255,255,255,255,0,0,1,0,0,0,0,0,0,0.5,0.5,1.8,0,0','fx_lissajous': '4096,0.9,0.9,3,8,7,0,0,0,0,0,0,0,0,255,255,255,255','samj_Orbites': '100,0,0,0,255,50,50,20,79,45,2,240,128,64,255,0,0,0,0,0,0,0,0','samj_Cercles_Tangents_Dans_Cercle': '50,50,50,40,0,0,0,0,255,1,127,127,127,127,255,0,0,127,0,255,0,127,0,0,255,127,255,0,255,127,255,255,0,127,0,255,255,127,192,128,64,127,64,192,128,127,128,64,192,127,192,64,128,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_en_Cercles_Tangents_Dans_Cercle': '50,50,50,40,0,0,0,0,255,1,127,127,127,127,255,0,0,127,0,255,0,127,0,0,255,127,255,0,255,127,255,255,0,127,0,255,255,127,192,128,64,127,64,192,128,127,128,64,192,127,192,64,128,127,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','Pintograph_samj': '50,50,192,128,64,255,0,0,1000,0,400,150,200,200,100,4.00,4.05,4.16,4.32,75,150,75,60,0,0,0,1,1','Pintograph_samj_en': '50,50,192,128,64,255,0,0,1000,0,400,150,200,200,100,4.00,4.05,4.16,4.32,75,150,75,60,0,0,0,1,1','fx_plasma': '0.5,0,8,0,0,128,128,128','fx_equation_plot': '"X*c+10*cos(X+c+u)",-10,10,100,3,2,0','samj_Arbre_Pythagore': '50,95,11,12,255,0,0,255,20,"A",1,0,0,0.25,10,0.8,0','fx_rainbow': '80,80,175,175,3,80','samj_Rosace_Triangles_Sierpinski': '6,6,50,50,50,-15,25,5,30,0,0,0,255,0,0,0,0,3,0,0,255,127,255,255,0,127,128,64,192,127,64,128,192,127,0,255,255,127,0,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_en_Linear_Gradient_CIE_Lab': '0,0,240,40,160,255,240,240,40,255','fx_shadebobs': '50,5,200,1,-1,2,1,0.8,0,8','samj_en_Cercles_Qui_Tournent': '800,255,255,255,255,0,1,0.5,0.33,7,17,1,0.5,0.33,7,17,1,10,0,0,0,255,0,0,0,0,0,0,0,0.5,0.5,1.8,0','samj_Formes_Geometriques_Simples': '50,50,127,127,127,127,255,255,0,255,0,0,255,255,5,40,40,4,0,0,1','samj_Lignes_Epaisseur_Variable': '0,32,3,0,0,0,255,255,255,255,255,0,0,1,0,0,0,0,0,0,0.5,0.5,1.8,0,0','fx_superformula': '4096,0.9,0.9,8,1,5,8,0,0,0,3,128,255,128,255','samj_Cercles_Qui_Tournent': '800,255,255,255,255,0,1,0.5,0.33,7,17,1,0.5,0.33,7,17,1,10,0,0,0,255,0,0,0,0,0,0,0,0.5,0.5,1.8,0','samj_en_Formes_Geometriques_Simples': '50,50,127,127,127,127,255,255,0,255,0,0,255,255,5,40,40,4,0,0,1','samj_Poisson_D_Avril': '50,50,40,2,0,0,0,0,255,1,250,60,10,255,255,255,255,255,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','banding_denoise': '5,5,5,10,0','samj_Superposition_Triangles_Sierpinski': '6,6,50,50,50,1,20,30,0,0,0,255,1,4,0,0,255,127,255,255,0,127,128,64,192,127,64,128,192,127,0,255,255,127,0,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_en_Flocon_De_Neige': '50,50,6,50,40,0,3,192,192,192,1,0,3,255,255,255,0.7,0,0,0,0,0,0,0,0,0.5,0.5,1.8,0,0,0,0','samj_Chains_Solidify': '50,50,0,6,56,20,50,0,255,0,221,255,72,0,255,255,0,145,255,255,0,255,144,255,72,255,0,255,255,217,0,255,255,0,0,255,5,255,127,0,255,0,0,0,255,100','bayer2rgb': '6,6,4','Traits_Strokes_samj': '50,50,35,0,100,0,30,0,360,240,60,120,255,0,0,0,20,0,0,0,1,1','samj_Palette_De_Degrades': '159,190,195,55,67,140,54,40,39,140,81,88,207,175,190,220,202,196,170,186,192,130,149,139,112,96,96,237,168,138,220,199,205,234,217,219,0,0,256,2','Spirographe_samj_en': '50,50,200,50,150,192,128,64,255,0,0,3,0,1,0,0,0,255,0,0,255,0,255,255,0,255,0,0,0,1,1','fx_tree': '11,10000,0,0,15,150,0,2.15,0.8,-40,40,10,75,0,70,20,40,25,0,255,100,70,140,60,255,100,0.4,0.4','afre_cleantext': '8,1,80,95','gcd_deinterlace2x': '40,0,0,2,0,1','Spirographe_samj': '50,50,200,50,150,192,128,64,255,0,0,3,0,1,0,0,0,255,0,0,255,0,255,255,0,255,0,0,0,1,1','samj_Splines_Test': '50,50,30,30,90,30,1,10,2,2,2,2,2,2,2,2,255,255,0,255,0,255,255,255,1,0,0','Triangles_Shades_Adjacents': '0,50,50,60,-1,0,255,255,255,255,0,221,72,0,255,0,145,255,0,255,144,72,255,0,255,217,0,255,0,0,5,0,0,128,128,128,1,0,3,1,0','fx_pahlsson_descreen': '0','samj_Des_Lignes_002': '100,0,0,192,128,64,255,0,0,1,50,50,0,0,0,0,1','samj_Test_Visu_3D': '1,"C:\\GimpEval-2.9.5-Win\\images_test\\GMIC\\cube.off",0.5,1,1,0,0,0,1,0,0,0,1024,1024,0.5,0,0,0,45,0,0,-100,0.5,0.7,2,1,400,1,225,255,255,255','fx_turbulence': '128,6,4,0,0','gcd_despeckle': '20,10','samj_en_Des_Lignes_002': '100,0,0,192,128,64,255,0,0,1,50,50,0,0,0,0,1','iain_fast_denoise_p': '0,0,1,0,0,0,1','Twisted_Rays_en': '800,1,0.2,2,5,21,0,0,0,0,255,255,0,255,255,255,0,255,0,255,255,255,0,255,255,0,0,255,255,0,255,255,255,255,255,255,0,0,0,0,255,0,2,2,0,0,5,0,0','iain_recursive_median_p': '3,1,0,0,1','fx_inpaint_holes': '4,20,1','iain_nr_2019': '1,0,0,0,0.5,1,0,5,3,0,3,0,.5,4,0','Twisted_Rays': '800,1,0.2,2,5,21,0,0,0,0,255,255,0,255,255,255,0,255,0,255,255,255,0,255,255,0,0,255,255,0,255,255,255,255,255,255,0,0,0,0,255,0,2,2,0,0,5,0,0','fx_inpaint_morpho': '255,0,0,255,0','jeje_scandoc': '3,1,90,5,0','rep_binary_quaddro_mc_gui': '0,0,0,0,1,2,0,1,2,3,0,1,2,3,4,0,8,8,128,2,0,0,0,1,0,8,8,128,2,0,0,0,1,0,8,8,128,2,0,0,0,1,0,8,8,128,2,0,0,0,1,0,8,8,128,2,0,0,0,1','jeje_local_wiener': '2,11,0,0','fx_inpaint_matchpatch': '0,9,10,5,1,255,0,0,255,0,0','samj_CorLine': '0,10,0.5,0,0,50,1,0','gui_rep_shape_brick': '150,150,5,5,0,0,0,0,0,0,170,0,0,255,85,0,0,255,121,77,2,255,0,41,100,0','jeje_unstrip': '1,20,4,1,0,0','rep_color_existence_distribution_rgb8': '1','samj_CorLine_B': '0,1,10,0,0,0,0.5,0,0,50,1,0','fx_inpaint_patch': '7,16,0.1,1.2,0,0.05,10,1,255,0,0,255,0,"100%"','jeje_denoise_patch_dict': '1,8,1.1,1.1,0,0','fx_inpaint_pde': '75,1,20,255,0,0,255,0','goof_res': '8,0,0,0','fx_scale_dcci2x': '1.15,5,0','-srand': '781123','jeje_denoise_iuwt': '3,4,2,0','fx_upscale_smart': '"200%","200%",2,0.4,50','fx_rep_nebulous': '0,4,10,10,0,0,0,1,0,0,1,0,0,0,0,2,0,1,3','iain_pixel_denoise_p': '2,1,11,0,1','sp': 'cliff','fx_scalenx': '0,0','rep_mj_newf': '16,0,0,128,9,0,75,5,10,50,50,45,0,0,0','plasma_transition': '0.5,5,1,42','fx_modulo': '1,0','fx_faded_mirror': '0,10,10','randomwaves': '84,80.,1.2,42','gui_rep_prime_surface': '0,0','fx_rep_rand_sqrrecfill': '0,0,15,2,1,1,0,1,1,1,0,0,0','gaap_test': '0,0,0,0','fx_adjust_orientation': '5','rep_binary_quaddro_basic_gui': '0,0,8,8,128,2,0,0,0,256,255,1,361,361','fx_gca': '255,255,255,1,0,0,0','fx_grain': '40,5,0,2,0.8,0.5,0.5,1,0,0.5,0.6,0.2,0.5,0','fx_apply_curve': '0,-1,128,-1,128,-1,128,-1,128,-1,128,255,1,0,0,0,0','fx_perspective_scale': '2,75,0,0,0','fx_lavalampbw': '3,30,1,20,2,0.01,0','gui_rep_tfrac': '0,0,10000,255,3,0,0,1,1,1,1,0,0,0,"atan2(a^2","b/sin(a)","sin(a)/cos(b)","b/cos(a)","a/sin(b)","b/cos(a+b)","a","b","a","b",0,3,0','KittyRings': '30,8,0,1,113,0,113,0,255,0','dt_segment_shaded': '1,0.7,1','fx_moire': '1,0,2,1,1,2,1,5','gui_layer_info': '1','fx_tk_make3D': '0,20,0,20,0,0,0,0,0,0,0,0,0,1.2,25,1,0,1,0,0,0,2,200','moon2panorama': '0,0,0,360,0,0,1,0,0','fx_text_pointcloud3d': '64,"G\'MIC","Rocks!",1,200,220,255,255,255,255,255,2,2,1,19','fx_tk_animateobject': '0,0,0,0.5,0.5,400,2,0,0,0,0,0,1,0,0,1','fx_tk_deana': '20,2','fx_souphead_filter': '0','fx_tk_depthmap': '0,20,0,0,0,0,0,0,0,0','fx_transition3d': '10,8,8,1,1,0,800,1','fx_tk_lenticular': '30,0,5,0,1,0','disco': '10,15,20,250','gcd_unstereo': '5,0.1,1,1,1,1,0','spiral_RGB': '1,3,5,0','fx_tk_retouch': '30,3,1,20,1.5,1,2.5,0,0,0','fx_tk_depth_obtain': '0,0.1,100,0','samj_CeKoaSa_001': '0,15,3,1,3,0','gcd_stereo_img': '0,0.5,1.2,1,0.25,2,4,1,0','mc_flou': '30,6,1,1,1,0,255,1,1,1,0','fx_tk_dof': '50,50,30,60,5,15,2,0,0,200,40,2,0,0,0,0,0.01,0,1,0,0','samj_CeKoaSa_002': '0,15,3,1,3,1,0','samj_CeKoaSa_003': '0,5,1,1,3,0','fx_tk_stereoimage': '0,0,1,0,1,0','mc_pendraw': '8,0.8,450,21,0.5,1,0,0,255,0,0','fx_tk_infrared': '0.75,0.5,-100,0.75,0,1,0,0,1,1,0,50,0','samj_CeKoaSa_005': '16,16,0,0,0.2,1,1,0,1,0','samj_BoxFiter_Map': '2,3,3,0,0,0,2,127,16,0,0,0.2','samj_BoxFiter_Test': '2,3,3,1,2','samj_CeKoaSa_004': '30,0,0,0.8,0,0','samj_CeKoaSa_007': '8,8,10,8,8','Polygonize_GUI': '300,10,10,10,10,0,0','samj_CeKoaSa_008': '64,64,4,1,2,16,1,20,0.1,0,1,64,1,2,10,0.8,255,255,255,255,0','samj_CeKoaSa_010': '30,10,0.1,2,10','samj_Relief_A': '3,1,0,1,16,1,50,1,1.0,1.2,1,1,1,1,1,1,0,0,0,0,0,0,100','samj_CeKoaSa_011': '0.2,0,0,5,0,0,0,0,240,40,160,255,240,240,40,255,0,50,205','samj_test_B': '100','samj_test_C': '100','samj_test_E': '0,0.7,0.3,0.6,1.1,0,200,125,50,0,1','samj_test_D': '40,255,10,30,5,0,8,0,4,0,25','samj_test_F': '40,50,1','samj_test_G': '0,0,0,30','fx_image_sample': '0,0,0','samj_Test_Solidify': '10,10,1,0.02,8,1,75,0,20','samj_test_x_color_curves': '1,0','samj_gimp_texture_zero_zero_deux': '0,10,4,10,0.5,1,1,1,0.3','samj_Texture_Aquarelle_1': '10,10,4,3,251,237,206,1','demo_xy': '1,1','samj_Toile_D_Araignee': '0,10,4','demo_ra': '1,1','mathmap_flag': '0.05,5,1,5','mathmap_spiral': '5,0'} 2 | -------------------------------------------------------------------------------- /examples/gmic-filters-default-parameters-to-operators/make_operators.py: -------------------------------------------------------------------------------- 1 | import json 2 | from default_parameters_gmic_py import default_parameters 3 | 4 | print("""import gmic 5 | import bpy 6 | gmic.default_parameters = {DEFAULT_PARAMETERS} 7 | """.format(DEFAULT_PARAMETERS=default_parameters)) 8 | 9 | operator_template = \ 10 | """ 11 | def gmic_enum_items_cb{OperatorSuffix}(self, context): 12 | l = {MenuItems} #(('ONE','One','First'), ('TWO','Two','Second'), ('THREE', 'Three', 'Third')) 13 | gmic_enum_items_cb{OperatorSuffix}.lookup = {{id: name for id, name, desc in l}} 14 | return l 15 | 16 | class GmicOperator{OperatorSuffix}(bpy.types.Operator): 17 | bl_idname = "object.gmic_operator{OperatorSuffix}" 18 | bl_label = "{Label}" 19 | 20 | myprop = bpy.props.EnumProperty(items=gmic_enum_items_cb{OperatorSuffix}) 21 | 22 | def execute(self, context): 23 | bpy.ops.render.render() 24 | bpy.data.images['Render Result'].save_render("somefile.tga") 25 | gmic.run("somefile.tga " + gmic.default_parameters[self.myprop] + " display") 26 | 27 | self.report({{'INFO'}}, gmic_enum_items_cb{OperatorSuffix}.lookup[self.myprop]) 28 | return {{'FINISHED'}} 29 | """ 30 | 31 | opLines = [] 32 | opline_template = "op = layout.operator_menu_enum(GmicOperator{OperatorSuffix}.bl_idname, 'myprop', text=GmicOperator{OperatorSuffix}.bl_label)" 33 | registerLines = [] 34 | register_template = "bpy.utils.register_class(GmicOperator{OperatorSuffix})" 35 | unregisterLines = [] 36 | unregister_template = "bpy.utils.unregister_class(GmicOperator{OperatorSuffix})" 37 | with open("/home/jd/Productions/GMIC/filters290.json", "r") as f: 38 | f_json = f.read() 39 | all_filters = json.loads(f_json) 40 | if all_filters: 41 | for pos, category in enumerate(all_filters["categories"]): 42 | print(operator_template.format(Label=category['name'], OperatorSuffix=pos, MenuItems=tuple((filter['command'], filter['command'], filter['command']) for filter in category['filters']))) 43 | opLines.append(" "*8 + opline_template.format(OperatorSuffix=pos)) 44 | registerLines.append(" "*4 + register_template.format(OperatorSuffix=pos)) 45 | unregisterLines.append(" "*4 + unregister_template.format(OperatorSuffix=pos)) 46 | 47 | custom_menu_template = \ 48 | """ 49 | class SimpleCustomMenu(bpy.types.Menu): 50 | bl_label = "G'MIC Quick Filters" 51 | bl_idname = "OBJECT_MT_simple_custom_menu" 52 | 53 | def draw(self, context): 54 | layout = self.layout 55 | {operatorLines} 56 | """ 57 | 58 | print(custom_menu_template.format(operatorLines="\n".join(opLines))) 59 | 60 | footer_template = \ 61 | """ 62 | def register(): 63 | {registerLines} 64 | bpy.utils.register_class(SimpleCustomMenu) 65 | 66 | def unregister(): 67 | {unregisterLines} 68 | bpy.utils.unregister_class(SimpleCustomMenu) 69 | 70 | if __name__ == "__main__": 71 | register() 72 | 73 | # The menu can also be called from scripts 74 | bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname) 75 | """ 76 | 77 | print(footer_template.format(registerLines="\n".join(registerLines), unregisterLines="\n".join(unregisterLines))) 78 | -------------------------------------------------------------------------------- /get_latest_gmicpy_version.py: -------------------------------------------------------------------------------- 1 | """ 2 | Prints the latest available gmic-py version from PyPI.org on standard output 3 | This comes in handy for Github CI scripts steps labels. 4 | """ 5 | 6 | import yolk.pypi 7 | PYPI_GMIC_PACKAGE_NAME="gmic" 8 | 9 | if __name__ == "__main__": 10 | releases = yolk.pypi.CheeseShop().package_releases(PYPI_GMIC_PACKAGE_NAME) 11 | releases.sort() 12 | print(releases[-1], end='') 13 | -------------------------------------------------------------------------------- /make_addon_requirements.txt: -------------------------------------------------------------------------------- 1 | yolk3k 2 | -------------------------------------------------------------------------------- /make_addon_zip.py: -------------------------------------------------------------------------------- 1 | """ 2 | Run this after installing the make_addon_requirements.txt with python 3.7 or more eg. in a virtual environment. 3 | It will create a freshest release of gmic-blender embedding gmic-py inside the downloads directory. 4 | """ 5 | 6 | import shutil 7 | import urllib.request, json 8 | import tempfile 9 | import os 10 | from distutils.dir_util import copy_tree 11 | import zipfile 12 | import re 13 | 14 | import yolk.pypi 15 | 16 | # CONSTANTS 17 | RELEASE_NAME = "gmic_blender" 18 | RELEASE_ADDONZIP_DIRECTORY_NAME = "downloads" 19 | ADDON_PATH = f"downloads/{RELEASE_NAME}.zip" 20 | PYPI_GMIC_PACKAGE_NAME = "gmic" 21 | GMICPY_DIRECTORY_NAME = "gmic-py" 22 | GMICPY_DOWNLOADS_CACHE_ENV_VARIABLE = "GMICPY_DOWNLOADS_CACHE" 23 | ASSETS_DIRECTORY_NAME = "assets" 24 | ASSETS_GMIC_FILTERS_JSON_PATH = os.path.join(ASSETS_DIRECTORY_NAME, "gmic_filters.json") 25 | BLENDER_ADDON_MODULE_FILE = "__init__.py" 26 | BLENDER_ADDON_README_FILE = "README.md" 27 | 28 | def is_skippable_wheel(filename): 29 | """Skip cpython and non-manylinux linux releases""" 30 | return re.match(r".*cpython.*|.*-linux-.*|.*manylinux2010.*", filename) is not None 31 | 32 | def is_targettable_python_version(filename): 33 | return re.match(r".*cp37.*", filename) is not None 34 | 35 | def get_simplified_directory_name_from_wheel(whl_filename): 36 | """ Return a full target directory path where a wheel should be extracted, that the Blender addon can generate 37 | The target expression on the Blender addon side will be: platform.system().lower() + "-" + platform.architecture()[0]""" 38 | parent_directory_name = os.path.dirname(whl_filename) 39 | target_subdirectory_name = os.path.basename(whl_filename).replace(".whl", "") 40 | if re.match(r".*macosx.*x86_64.*", whl_filename): 41 | target_subdirectory_name = "darwin-64bit" 42 | elif re.match(r".*linux.*x86_64.*", whl_filename): 43 | target_subdirectory_name = "linux-64bit" 44 | elif re.match(r".*linux.*686.*", whl_filename): 45 | target_subdirectory_name = "linux-32bit" 46 | # Add support for macosx 32bit (or not..) and for Windows 47 | return os.path.join(parent_directory_name, target_subdirectory_name) 48 | 49 | def _download_and_unzip_wheel_files(dirpath, latest_release_data): 50 | for release in latest_release_data: 51 | if is_targettable_python_version(release["filename"]): 52 | if is_skippable_wheel(release["filename"]): 53 | continue 54 | release_filename = os.path.basename(release["url"]) 55 | 56 | if is_skippable_wheel(release_filename): 57 | continue 58 | 59 | if os.path.exists(os.path.join(dirpath, release_filename)): 60 | print(f"Found cached {release_filename}") 61 | else: 62 | print(f"Will download {release_filename} into {dirpath}") 63 | print(release["url"]) 64 | datatowrite = urllib.request.urlopen(release["url"]).read() 65 | with open(os.path.join(dirpath, release_filename), "wb") as f: 66 | f.write(datatowrite) 67 | copy_tree(dirpath, GMICPY_DIRECTORY_NAME) 68 | import glob 69 | whl_files = glob.glob(f"./{GMICPY_DIRECTORY_NAME}/*.whl") 70 | for whl_file in whl_files: 71 | extract_target_path = get_simplified_directory_name_from_wheel(whl_file) 72 | print(f"Extracting wheel {whl_file} into {extract_target_path}") 73 | with zipfile.ZipFile(whl_file, 'r') as zipObj: 74 | zipObj.extractall(extract_target_path) 75 | os.unlink(whl_file) 76 | 77 | def download_gmicpy_wheel_files(): 78 | releases = yolk.pypi.CheeseShop().package_releases(PYPI_GMIC_PACKAGE_NAME) 79 | releases.sort() 80 | latest_release_data = yolk.pypi.CheeseShop().release_urls(PYPI_GMIC_PACKAGE_NAME, releases[-1]) 81 | 82 | tempdir = os.environ.get(GMICPY_DOWNLOADS_CACHE_ENV_VARIABLE, False) 83 | if tempdir: 84 | print(f"Detected cache path for Gmic Python wheel downloads: {tempdir}") 85 | tempdir = os.path.expanduser(tempdir) 86 | if not os.path.exists(tempdir): 87 | print(f"Creating non-existing configured cache path: {tempdir}") 88 | os.makedirs(tempdir) 89 | _download_and_unzip_wheel_files(tempdir, latest_release_data) 90 | else: 91 | with tempfile.TemporaryDirectory() as dirpath: 92 | _download_and_unzip_wheel_files(dirpath, latest_release_data) 93 | 94 | def clean_old_directories(): 95 | shutil.rmtree(RELEASE_ADDONZIP_DIRECTORY_NAME, ignore_errors=True) 96 | shutil.rmtree(GMICPY_DIRECTORY_NAME, ignore_errors=True) 97 | shutil.rmtree(RELEASE_NAME, ignore_errors=True) 98 | 99 | def setup_addon_files(): 100 | # Copy addon files into the RELEASE_NAME directory 101 | # The RELEASE_ADDONZIP_DIRECTORY_NAME directory is for final archives 102 | os.mkdir(RELEASE_ADDONZIP_DIRECTORY_NAME) 103 | os.mkdir(RELEASE_NAME) 104 | 105 | shutil.copy(BLENDER_ADDON_MODULE_FILE, RELEASE_NAME) 106 | shutil.copy(BLENDER_ADDON_README_FILE, RELEASE_NAME) 107 | copy_tree(GMICPY_DIRECTORY_NAME, RELEASE_NAME) 108 | 109 | # TODO This json file will be useless from gmic 2.9.0 110 | assets_dir = os.path.join(RELEASE_NAME, ASSETS_DIRECTORY_NAME) 111 | os.makedirs(assets_dir) 112 | shutil.copy(ASSETS_GMIC_FILTERS_JSON_PATH, assets_dir) 113 | 114 | def zip_addon_files(): 115 | # Per https://www.tutorialspoint.com/How-to-zip-a-folder-recursively-using-Python 116 | def zipdir(path, ziph): 117 | # ziph is zipfile handle 118 | for root, dirs, files in os.walk(path): 119 | for file in files: 120 | ziph.write(os.path.join(root, file)) 121 | zipf = zipfile.ZipFile(ADDON_PATH, 'w', zipfile.ZIP_DEFLATED) 122 | zipdir(RELEASE_NAME, zipf) 123 | zipf.close() 124 | 125 | def make_addon_zip(): 126 | clean_old_directories() 127 | # Grab gmic-py .whl(s) from Pypi.org and extract them 128 | download_gmicpy_wheel_files() 129 | setup_addon_files() 130 | zip_addon_files() 131 | shutil.rmtree(RELEASE_NAME) 132 | shutil.rmtree(GMICPY_DIRECTORY_NAME) 133 | print(f"here you are :) static add-on to test in Blender: {ADDON_PATH}") 134 | 135 | if __name__ == "__main__": 136 | make_addon_zip() 137 | -------------------------------------------------------------------------------- /test_gmic_blender_addon.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import blender_addon_tester as BAT 4 | 5 | addon_path = "downloads/gmic_blender.zip" 6 | 7 | def usage(): 8 | print("{}: [blender_version]".format(sys.argv[0])) 9 | print("Tests the {} addon archive on blender_version for your OS only (MacOS or Linux)".format(sys.argv[0])) 10 | print("A pytest coverage report is saved to coverage.xml in the current directory at the end of the test.") 11 | print("If the blender_version argument is not provided. The BLENDER_VERSION environment variable is checked. Else 2.80 is assumed.") 12 | print("This script requires the blender-addon-tester Python module installed first, see requirements.txt or install yourself with pip.") 13 | 14 | if __name__ == "__main__": 15 | blender_revision = None 16 | if len(sys.argv) > 1: 17 | blender_revision = sys.argv[1] 18 | else: 19 | blender_revision = os.environ.get("BLENDER_VERSION", False) 20 | if not blender_revision: 21 | print("No blender_revision CLI argument or BLENDER_VERSION environment variable found, defaulting to Blender 2.80 for testing!") 22 | config = {"coverage": True} 23 | 24 | BAT.test_blender_addon(addon_path=addon_path, blender_revision=blender_revision, config=config) 25 | -------------------------------------------------------------------------------- /tests/test_version_and_gmicpy_import.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from addon_helper import get_version 3 | 4 | 5 | @pytest.fixture 6 | def bpy_module(cache): 7 | return cache.get("bpy_module", None) 8 | 9 | 10 | def test_versionID_pass(bpy_module): 11 | expect_version = (0, 0, 1) 12 | return_version = get_version(bpy_module) 13 | assert expect_version == return_version 14 | 15 | 16 | def test_versionID_fail(bpy_module): 17 | expect_version = (0, 1, 1) 18 | return_version = get_version(bpy_module) 19 | assert not expect_version == return_version 20 | 21 | def test_gmic_loaded(): 22 | import gmic 23 | assert type(gmic.Gmic.run).__name__ == 'method_descriptor' 24 | --------------------------------------------------------------------------------