CINXE.COM
Adding new ops
<!DOCTYPE html> <html> <head> <title>Adding new ops</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=3" /> <meta content="ImageJ Wiki" property="og:site_name"> <meta content="Adding new ops" property="og:title"> <meta content="article" property="og:type"> <meta content="The ImageJ wiki is a community-edited knowledge base on topics relating to ImageJ, a public domain program for processing and analyzing scientific images, and its ecosystem of derivatives and variants, including ImageJ2, Fiji, and others." property="og:description"> <meta content="https://imagej.github.io/develop/writing-ops" property="og:url"> <meta content="https://imagej.github.io/media/icons/imagej2.png" property="og:image"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> <link rel="manifest" href="/site.webmanifest"> <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"> <meta name="msapplication-TileColor" content="#da532c"> <meta name="theme-color" content="#ffffff"> <link rel="stylesheet" href="/assets/css/lightbox.min.css" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/algolia-min.css"/> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/dygraphs@2.1.0/dist/dygraph.min.js"></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/dygraphs@2.1.0/dist/dygraph.min.css" /> <link rel="stylesheet" href="/assets/css/main.css" /> <link rel="stylesheet" href="/assets/css/layout.css"/> <link rel="stylesheet" href="/assets/css/includes.css" /> <link rel="stylesheet" href="/assets/css/timeline.css"/> <link rel="stylesheet" href="/assets/css/dock.css"/> <noscript><link rel="stylesheet" href="/assets/css/noscript.css" /></noscript> <link rel="stylesheet" href="/assets/css/page.css" /> </head> <body class="is-preload"> <!-- Top bar --> <section id="top-bar"> <a href="/"><img id="site-logo" src="/media/icons/imagej2.png"></a> <div id="search-panel"> <div id="search-box"></div> </div> </section> <!-- Page-info --> <div class="page-info"> <a href="https://github.com/imagej/imagej.github.io/commits/main/_pages/develop/writing-ops.md">Page history</a> <a href="https://github.com/imagej/imagej.github.io/edit/main/_pages/develop/writing-ops.md">Edit this page</a> <a href="/editing">How do I edit this website?</a></div> <section id="left-column" class="sidebar dock"> <!-- Menu --> <div class="menu dockable"> <div class="drag-handle"></div><h3>ImageJ Docs</h3> <ul> <li><a href="/downloads">Download</a></li> <li><details><summary>Learn</summary><ul> <li><details><summary><a href="/learn">ImageJ Basics</a></summary><ul> <li><a href="/tutorials">Tutorials</a></li> <li><a href="/learn/user-guides">User Guides</a></li> <li><a href="/learn/keyboard-shortcuts">Keyboard Shortcuts</a></li> <li><a href="/learn/tips-and-tricks">Tips and Tricks</a></li> <li><a href="/learn/troubleshooting">Troubleshooting</a></li> <li><a href="/learn/faq">Frequently Asked Questions</a></li> <li><details><summary><a href="/platforms">Supported Platforms</a></summary><ul> <li><a href="/platforms/windows">Windows</a></li> <li><a href="/platforms/macos">MacOS</a></li> <li><a href="/platforms/linux">Linux</a></li> <li><a href="/platforms/pi">Raspberry Pi</a></li> <li><a href="/platforms/android">Android</a></li> </ul></details></li> <!-- Learn/ImageJ Basics/Supported Platforms --> <li><details><summary><a href="/formats">File Formats</a></summary><ul> <li><a href="/formats/bio-formats">Bio-Formats</a></li> <li><a href="/formats/video">Video formats</a></li> <li><a href="/formats/quicktime">QuickTime</a></li> <li><a href="/formats/tiff">TIFF</a></li> <li><a href="/formats/pdf">PDF</a></li> <li><a href="/formats/dicom">DICOM</a></li> <li><a href="/formats/lsm">Zeiss LSM</a></li> <li><a href="/formats/olympus">Olympus VSI</a></li> <li><a href="/formats/lurawave">Opera Flex</a></li> <li><a href="/formats/fib-sem">FIB-SEM</a></li> </ul></details></li> <!-- Learn/ImageJ Basics/File Formats --> </ul></details></li> <!-- Learn/ImageJ --> <li><details><summary><a href="/imaging">Scientific Imaging</a></summary><ul> <li><a href="/imaging/principles">Principles of Scientific Imaging</a></li> <li><a href="/imaging/annotating-images">Annotating Images</a></li> <li><a href="/imaging/colocalization-analysis">Colocalization</a></li> <li><a href="/imaging/color-image-processing">Color Image Processing</a></li> <li><a href="/imaging/deconvolution">Deconvolution</a></li> <li><a href="/imaging/image-intensity-processing">Image Intensity Processing</a></li> <li><a href="/imaging/particle-analysis">Particle Analysis</a></li> <li><a href="/imaging/registration">Registration</a></li> <li><a href="/imaging/segmentation">Segmentation</a></li> <li><a href="/imaging/stack-slice-manipulations">Stack-slice Manipulations</a></li> <li><a href="/imaging/t-functions">T-functions</a></li> <li><a href="/imaging/tracking">Tracking</a></li> <li><a href="/imaging/visualization">Visualization</a></li> <li><a href="/imaging/z-functions">Z-functions</a></li> </ul></details></li> <!-- Learn/Scientific Imaging --> </ul></details></li> <!-- Learn --> <li><details open><summary><a href="/plugins">Extend</a></summary><ul> <li><a href="/list-of-extensions">List of Extensions</a></li> <li><details><summary><a href="/update-sites">Update Sites</a></summary><ul> <li><a href="/list-of-update-sites">List of Update Sites</a></li> <li><a href="/update-sites/following">Following an Update Site</a></li> <li><a href="/update-sites/setup">Creating an Update Site</a></li> <li><a href="/update-sites/tos">Terms of Service</a></li> <li><a href="/update-sites/automatic-uploads">Automatic Upload</a></li> <li><a href="/update-sites/core-uploads">Uploading to Core Sites</a></li> <li><a href="/update-sites/faq">Update Sites FAQ</a></li> <li><a href="/update-sites/stats">Statistics</a></li> </ul></details></li> <!-- Extend/Update Sites --> <li><details><summary><a href="/scripting">Scripting</a></summary><ul> <li><a href="/scripting/basics">Scripting Basics</a></li> <li><a href="/scripting/script-editor">Script Editor</a></li> <li><a href="/scripting/parameters">Parameters</a></li> <li><a href="/scripting/user-input">User Input</a></li> <li><a href="/scripting/auto-imports">Auto Import</a></li> <li><a href="/scripting/templates">Templates</a></li> <li><a href="/scripting/batch">Batch Processing</a></li> <li><a href="/scripting/headless">Running Headlessly</a></li> <li><a href="/scripting/comparisons">Scripting Comparisons</a></li> <li><a href="/scripting/toolbox">Toolbox</a></li> <li><details><summary>Languages</summary><ul> <li><a href="/scripting/beanshell">BeanShell Scripting</a></li> <li><a href="/scripting/groovy">Groovy Scripting</a></li> <li><a href="/scripting/macro">ImageJ Macro</a></li> <li><a href="/scripting/javascript">JavaScript</a></li> <li><a href="/scripting/clojure">Lisp (Clojure)</a></li> <li><a href="/scripting/matlab">MATLAB</a></li> <li><a href="/scripting/jython">Python (Jython)</a></li> <li><a href="/scripting/python">Python (native)</a></li> <li><a href="/scripting/renjin">R (Renjin)</a></li> <li><a href="/scripting/jruby">Ruby (JRuby)</a></li> <li><a href="/scripting/scala">Scala Scripting</a></li> </ul></details></li> <!-- Extend/Scripting/Languages --> </ul></details></li> <!-- Extend/Scripting --> <li><details open><summary><a href="/develop">Development</a></summary><ul> <li><a href="/develop/philosophy">Philosophy</a></li> <li><a href="/develop/architecture">Architecture</a></li> <li><a href="/develop/source">Source code</a></li> <li><a href="/develop/project-management">Project management</a></li> <li><a href="/develop/coding-style">Coding style</a></li> <li><a href="/develop/javadoc">Using Javadoc</a></li> <li><a href="/develop/debugging">Debugging</a></li> <li><a href="/develop/wish-list">Wish list</a></li> <li><details><summary>Tools</summary><ul> <li><a href="/develop/github">GitHub</a></li> <li><a href="/develop/maven">Maven</a></li> <li><a href="/develop/ci">CI/CD</a></li> <li><a href="/develop/dotfiles">Dotfiles</a></li> <li><details><summary><a href="/develop/ides">IDEs</a></summary><ul> <li><a href="/develop/eclipse">Eclipse</a></li> <li><a href="/develop/netbeans">NetBeans</a></li> <li><a href="/develop/intellij">IntelliJ IDEA</a></li> <li><a href="/develop/command-line">Command Line</a></li> </ul></details></li> </ul></details></li> <!-- Extend/Development/Tools --> <li><details open><summary>Guides</summary><ul> <li><a href="/develop/plugins">Writing plugins</a></li> <li><a href="/develop/improving-the-code">Contributing to a plugin</a></li> <li><a href="/develop/releasing">Development lifecycle</a></li> <li><a href="/develop/building-a-pom">Building a POM</a></li> <li><a href="/develop/debugging-exercises">Hands-on debugging</a></li> <li><a class="current-page">Adding new ops</a></li> <li><a href="/develop/formats">Adding new formats</a></li> <li><a href="/develop/native-libraries">Using native libraries</a></li> <li><a href="/develop/tips">Tips for developers</a></li> <li><a href="/develop/cpp-tips">Tips for C++ developers</a></li> <li><a href="/develop/ij1-plugins">ImageJ 1.x plugins</a></li> <li><a href="/develop/versioning">Versioning</a></li> <li><a href="/develop/logging">Logging</a></li> <li><a href="/develop/uber-jars">Uber-JARs</a></li> </ul></details></li> <!-- Extend/Development/Guides --> <li><details><summary><a href="/develop/git">Git</a></summary><ul> <li><a href="/develop/git/eclipse">Git in Eclipse (EGit)</a></li> <li><a href="/develop/git/mini-howto">Git mini howto</a></li> <li><a href="/develop/git/workshop">Git workshop</a></li> <li><a href="/develop/git/conflicts">Git conflicts</a></li> <li><a href="/develop/git/topic-branches">Git topic branches</a></li> <li><a href="/develop/git/notes">Git notes</a></li> <li><a href="/develop/git/reflogs">Git reflogs</a></li> <li><a href="/develop/git/submodules">Git submodules</a></li> <li><a href="/develop/git/pinpoint-regressions">How to pinpoint regressions</a></li> <li><a href="/develop/git/publish-a-repository">How to publish a git repository</a></li> <li><a href="/develop/git/extract-a-subproject">How to extract a subproject</a></li> </ul></details></li> <!-- Extend/Development/Git --> </ul></details></li> <!-- Extend/Development --> </ul></details></li> <!-- Extend --> <li><details><summary><a href="/contribute">Contribute</a></summary><ul> <li><a href="/contribute/citing">Citing</a></li> <li><a href="/people">Contributors</a></li> <li><a href="/orgs">Organizations</a></li> <li><a href="/contribute/governance">Governance</a></li> <li><a href="/contribute/funding">Funding</a></li> <li><a href="/contribute/fiji">Contributing to Fiji</a></li> <li><details><summary><a href="/licensing">Licensing</a></summary><ul> <li><details><summary><a href="/licensing/open-source">Open Source</a></summary><ul> <li><a href="/licensing/apache">Apache</a></li> <li><a href="/licensing/bsd">BSD</a></li> <li><a href="/licensing/epl">EPL</a></li> <li><a href="/licensing/gpl">GPL</a></li> <li><a href="/licensing/lgpl">LGPL</a></li> <li><a href="/licensing/mit">MIT</a></li> <li><a href="/licensing/public-domain">Public domain</a></li> <li><a href="/licensing/big">BIG</a></li> </ul></details></li> <!-- Contribute/Licensing/Open Source --> <li><a href="/licensing/closed-source">Proprietary</a></li> </ul></details></li> <!-- Contribute/Licensing --> <li><details><summary><a href="/editing">Editing the Wiki</a></summary><ul> <li><a href="/editing/advanced">Advanced Editing</a></li> <li><a href="/editing/buttons">Buttons</a></li> <li><a href="/editing/citations">Citations</a></li> <li><a href="/editing/code">Source Code</a></li> <li><a href="/editing/debugging">Debugging</a></li> <li><a href="/editing/headers">Headers</a></li> <li><a href="/editing/icons">Icons</a></li> <li><a href="/editing/images">Images</a></li> <li><a href="/editing/keys">Keyboard Shortcuts</a></li> <li><a href="/editing/linking">Linking</a></li> <li><a href="/editing/math">Math Expressions</a></li> <li><a href="/editing/menu-paths">Menu Paths</a></li> <li><a href="/editing/navigation">Navigation</a></li> <li><a href="/editing/notices">Notices</a></li> <li><a href="/editing/people">People</a></li> <li><a href="/editing/pitfalls">Pitfalls</a></li> <li><a href="/editing/quizzes">Quizzes</a></li> <li><a href="/editing/statbox">Statbox</a></li> <li><a href="/editing/symbols">Symbols</a></li> <li><a href="/editing/tables">Tables</a></li> <li><a href="/editing/timelines">Timelines</a></li> <li><a href="/editing/tooltips">Tooltips</a></li> <li><a href="/editing/videos">Videos</a></li> <li><a href="/editing/whitespace">Whitespace</a></li> </ul></details></li> <!-- Contribute/Editing the Wiki --> </ul></details></li> <!-- Contribute --> <li><details><summary><a href="/discuss">Discuss</a></summary><ul> <li><a href="/discuss/bugs">Reporting Issues</a></li> <li><a href="/discuss/mailing-lists">Mailing Lists</a></li> <li><a href="/discuss/chat">Chat</a></li> </ul></details></li> <!-- Discuss --> <li><details><summary>Explore</summary><ul> <li><a href="/news">News</a></li> <li><details><summary><a href="/events">Events</a></summary><ul> <li><a href="/events/presentations">Presentations</a></li> <li><a href="/events/conferences">Conferences</a></li> <li><a href="/events/hackathons">Hackathons</a></li> <li><a href="/events">More...</a></li> </ul></details></li> <!-- Discuss/Events --> <li><details><summary><a href="/libs">Libraries</a></summary><ul> <li><a href="/libs/imagej-ops">ImageJ Ops</a></li> <li><a href="/libs/imagej-common">ImageJ Common</a></li> <li><a href="/libs/imagej-legacy">ImageJ Legacy</a></li> <li><a href="/libs/scijava">SciJava</a></li> <li><a href="/libs/scifio">SCIFIO</a></li> <li><details><summary><a href="/libs/imglib2">ImgLib2</a></summary><ul> <li><a href="/libs/imglib2/getting-started">Getting Started</a></li> <li><a href="/libs/imglib2/accessors">Accessors</a></li> <li><a href="/libs/imglib2/accessibles">Accessibles</a></li> <li><a href="/libs/imglib2/examples">Examples</a></li> <li><a href="/libs/imglib2/workshop-introductory">Introductory Workshop</a></li> <li><a href="/libs/imglib2/workshop-advanced">Advanced Workshop</a></li> <li><a href="/libs/imglib2/matlab">ImgLib2 images in MATLAB</a></li> <li><a href="/libs/imglib2/benchmarks">Benchmarks</a></li> <li><a href="/libs/imglib2/faq">FAQ</a></li> <li><a href="/libs/imglib2/developing">Developing ImgLib2</a></li> <li><a href="/libs/imglib2/discussion">ImgLib2 Discussion</a></li> </ul></details></li> <!-- Explore/Libraries/ImgLib2 --> <li><a href="/libs">More...</a></li> </ul></details></li> <!-- Explore/Libraries --> <li><details><summary><a href="/software">Software</a></summary><ul> <li><a href="/software/nih-image">NIH Image</a></li> <li><a href="/software/imagej">ImageJ</a></li> <li><a href="/software/imagej2">ImageJ2</a></li> <li><a href="/software/fiji">Fiji</a></li> <li><a href="/software">More...</a></li> </ul></details></li> <!-- Explore/Software --> </ul></details></li> <!-- Explore --> </ul> </div> </section> <section id="right-column" class="sidebar dock"> <!-- Vital stats --> <!-- Table of contents --> <div id="toc" class="toc menu dockable"> <div class="drag-handle"></div> <h3>Page contents</h3> <ul data-toc="#content" data-toc-headings="h1,h2,h3,h4,h5,h6"></ul> </div> </section> <!-- Page title --> <div class="container"> <header class="major special"> <h1>Adding new ops</h1> </header> </div> <!-- Nav bar --> <!-- Main content --> <section id="page" class="main style1"> <div class="container"> <div class="box alt"></div> <div id="content" class="page-content"> <p>This tutorial is designed to guide developers through the options, processes and motivations for adding Ops outside the core <a href="https://github.com/imagej/imagej-ops/">imagej-ops</a> project. Because this tutorial caters to external developers, in this tutorial we show how a <a href="/plugins/bar">BAR</a> function could be converted to an Op.</p> <h1 id="make-your-first-op">Make your first Op</h1> <p>At the most fundamental level, an Op is a SciJava <a href="https://github.com/scijava/scijava-common/blob/scijava-common-2.47.0/src/main/java/org/scijava/plugin/Plugin.java">Plugin</a> encapsulating a piece of functionality, which can be discovered and used by a central <a href="https://github.com/imagej/imagej-ops/blob/imagej-ops-0.18.0/src/main/java/net/imagej/ops/OpService.java">OpService</a>.</p> <p>At a minimum, creating an Op requires two pieces - an interface, and an implementation</p> <h2 id="create-your-interface">Create your Interface</h2> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">bar</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.imagej.ops.Op</span><span class="o">;</span> <span class="cm">/** * Op interface for calculating the greatest common divisor (GCD) */</span> <span class="kd">public</span> <span class="kd">interface</span> <span class="nc">GCD</span> <span class="kd">extends</span> <span class="nc">Op</span> <span class="o">{</span> <span class="c1">// Ops can be called by name, defined as properties of the Op interface</span> <span class="nc">String</span> <span class="no">NAME</span> <span class="o">=</span> <span class="s">"gcd"</span><span class="o">;</span> <span class="c1">// An alias is OPTIONAL but gives users additional ways to call your Op.</span> <span class="c1">// For example - the GCD is also called greatest common factor (GCF).</span> <span class="nc">String</span> <span class="no">ALIASES</span> <span class="o">=</span> <span class="s">"gcf"</span><span class="o">;</span> <span class="o">}</span> </code></pre></div></div> <h2 id="implement-your-op">Implement your Op</h2> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">bar</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.imagej.ops.AbstractOp</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.ItemIO</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.plugin.Attr</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.plugin.Parameter</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.plugin.Plugin</span><span class="o">;</span> <span class="c1">// The Plugin annotation allows this Op to be discovered by the OpService.</span> <span class="c1">// We declare the type of op; the name and any aliases will be auto-detected.</span> <span class="nd">@Plugin</span><span class="o">(</span><span class="n">type</span> <span class="o">=</span> <span class="no">GCD</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">DefaultGCD</span> <span class="kd">implements</span> <span class="no">GCD</span> <span class="kd">extends</span> <span class="nc">AbstractOp</span> <span class="o">{</span> <span class="c1">// -- Inputs --</span> <span class="c1">// We want our GCD function to have two inputs. These are declared using @Parameter notation</span> <span class="nd">@Parameter</span> <span class="kd">private</span> <span class="kt">double</span> <span class="n">a</span><span class="o">;</span> <span class="nd">@Parameter</span> <span class="kd">private</span> <span class="kt">double</span> <span class="n">b</span><span class="o">;</span> <span class="c1">// -- Outputs --</span> <span class="c1">// This op will return a single value (the computed GCD) so we declare an output parameter</span> <span class="nd">@Parameter</span><span class="o">(</span><span class="n">type</span> <span class="o">=</span> <span class="nc">ItemIO</span><span class="o">.</span><span class="na">OUTPUT</span><span class="o">)</span> <span class="kd">private</span> <span class="kt">double</span> <span class="n">result</span><span class="o">;</span> <span class="nd">@Override</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="o">()</span> <span class="o">{</span> <span class="c1">// The job of the run method is to populate any outputs using the inputs</span> <span class="n">result</span> <span class="o">=</span> <span class="n">computeGCD</span><span class="o">(</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">);</span> <span class="o">}</span> <span class="kd">private</span> <span class="kt">double</span> <span class="nf">computeGCD</span><span class="o">(</span><span class="kd">final</span> <span class="kt">double</span> <span class="n">p1</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">double</span> <span class="n">p2</span><span class="o">)</span> <span class="o">{</span> <span class="k">return</span> <span class="n">p2</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">p1</span> <span class="o">:</span> <span class="n">computeGCD</span><span class="o">(</span><span class="n">p2</span><span class="o">,</span> <span class="n">p1</span><span class="o">%</span><span class="n">p2</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p><a href="https://github.com/tferr/Scripts/blob/-/BAR/src/main/java/bar/DefaultGCD.java">On GitHub</a></p> <h2 id="use-your-op">Use your Op</h2> <p>With these two components, you can start using your Op - for example, in the <a href="/scripting">script editor</a>:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># @OpService ops </span> <span class="kn">from</span> <span class="nn">bar</span> <span class="kn">import</span> <span class="n">GCD</span> <span class="c1"># We look up our Op by asking the framework to find an implementation of the # GCD interface that could handle these inputs </span><span class="n">gcd</span> <span class="o">=</span> <span class="n">ops</span><span class="p">.</span><span class="n">op</span><span class="p">(</span><span class="n">GCD</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span> <span class="c1"># Print the Op instance, to verify our Op is picked up </span><span class="k">print</span><span class="p">(</span><span class="n">gcd</span><span class="p">)</span> <span class="c1"># The OpService can print useful information about any Op.. </span><span class="k">print</span><span class="p">(</span><span class="n">ops</span><span class="p">.</span><span class="n">info</span><span class="p">(</span><span class="n">gcd</span><span class="p">))</span> <span class="c1"># .. including its usage </span><span class="k">print</span><span class="p">(</span><span class="n">ops</span><span class="p">.</span><span class="n">help</span><span class="p">(</span><span class="s">"gcd"</span><span class="p">))</span> <span class="c1"># We can also run an Op by passing the name or alias we defined # Print the result of running our Op </span><span class="k">print</span><span class="p">(</span><span class="n">ops</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="s">"gcf"</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span> </code></pre></div></div> <h1 id="group-your-ops-in-a-namespace">Group your Ops in a Namespace</h1> <p>Calling our Ops by name is not type-safe, and importing each interface is tedious. If you are going to provide a collection of Ops, a useful way to package them is within a custom <a href="http://javadoc.scijava.org/ImageJ/net/imagej/ops/Namespace.html">Namespace</a>.</p> <h2 id="create-your-interfaces">Create your Interface(s)</h2> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">bar</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.plugin.Plugin</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.imagej.ops.AbstractNamespace</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.imagej.ops.Namespace</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.imagej.ops.Op</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.imagej.ops.OpMethod</span><span class="o">;</span> <span class="nd">@Plugin</span><span class="o">(</span><span class="n">type</span> <span class="o">=</span> <span class="nc">Namespace</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">BAR</span> <span class="kd">extends</span> <span class="nc">AbstractNamespace</span> <span class="o">{</span> <span class="nd">@Override</span> <span class="kd">public</span> <span class="nc">String</span> <span class="nf">getName</span><span class="o">()</span> <span class="o">{</span> <span class="k">return</span> <span class="s">"name"</span><span class="o">;</span> <span class="o">}</span> <span class="c1">// -- BAR Namespace Op interfaces --</span> <span class="c1">// We can make all of our interfaces nested classes.</span> <span class="c1">// This allows references to take the form of "Namespace.Op" which</span> <span class="c1">// can make things easier to understand.</span> <span class="kd">public</span> <span class="kd">interface</span> <span class="nc">GCD</span> <span class="kd">extends</span> <span class="nc">Op</span> <span class="o">{</span> <span class="c1">// Note that the name and aliases are prepended with Namespace.getName</span> <span class="nc">String</span> <span class="no">NAME</span> <span class="o">=</span> <span class="s">"bar.gcd"</span><span class="o">;</span> <span class="nc">String</span> <span class="no">ALIASES</span> <span class="o">=</span> <span class="s">"bar.gcf"</span><span class="o">;</span> <span class="o">}</span> <span class="c1">// -- BAR Namespace built-in methods --</span> <span class="c1">// Built-in methods provide type-safe methods for accessing Ops</span> <span class="c1">// in a namespace.</span> <span class="c1">// We always provide an Object... constructor that can be passed directly to the</span> <span class="c1">// OpService.run method</span> <span class="nd">@OpMethod</span><span class="o">(</span><span class="n">op</span> <span class="o">=</span> <span class="n">bar</span><span class="o">.</span><span class="na">BAR</span><span class="o">.</span><span class="na">GCD</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="kd">public</span> <span class="nc">Object</span> <span class="nf">gcd</span><span class="o">(</span><span class="kd">final</span> <span class="nc">Object</span><span class="o">...</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span> <span class="k">return</span> <span class="nf">ops</span><span class="o">().</span><span class="na">run</span><span class="o">(</span><span class="n">bar</span><span class="o">.</span><span class="na">BAR</span><span class="o">.</span><span class="na">GCD</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">args</span><span class="o">);</span> <span class="o">}</span> <span class="c1">// But we can also type-narrow our inputs and returns with our knowledge of the Op</span> <span class="c1">// implementations</span> <span class="nd">@OpMethod</span><span class="o">(</span><span class="n">op</span> <span class="o">=</span> <span class="n">bar</span><span class="o">.</span><span class="na">BAR</span><span class="o">.</span><span class="na">GCD</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="kd">public</span> <span class="kt">double</span> <span class="nf">gcd</span><span class="o">(</span><span class="kd">final</span> <span class="kt">double</span> <span class="n">a</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">double</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span> <span class="k">return</span> <span class="o">(</span><span class="nc">Double</span><span class="o">)</span> <span class="n">ops</span><span class="o">().</span><span class="na">run</span><span class="o">(</span><span class="n">bar</span><span class="o">.</span><span class="na">BAR</span><span class="o">.</span><span class="na">GCD</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p><a href="https://github.com/tferr/Scripts/blob/-/BAR/src/main/java/bar/BAR.java">On GitHub</a></p> <h2 id="implement-your-ops">Implement your Op(s)</h2> <p>The implementation is essentially the same as with single Ops, although we do have to update our class references.</p> <p>Since the implementations are not accessed directly typically, whether they are grouped as nested classes or provided individually is less important than for the interfaces.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">bar</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.imagej.ops.AbstractOp</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.ItemIO</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.plugin.Attr</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.plugin.Parameter</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.plugin.Plugin</span><span class="o">;</span> <span class="nd">@Plugin</span><span class="o">(</span><span class="n">type</span> <span class="o">=</span> <span class="no">BAR</span><span class="o">.</span><span class="na">GCD</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">name</span> <span class="o">=</span> <span class="no">BAR</span><span class="o">.</span><span class="na">GCD</span><span class="o">.</span><span class="na">NAME</span><span class="o">,</span> <span class="n">attrs</span> <span class="o">=</span> <span class="o">{</span> <span class="nd">@Attr</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"aliases"</span><span class="o">,</span> <span class="n">value</span> <span class="o">=</span> <span class="no">BAR</span><span class="o">.</span><span class="na">GCD</span><span class="o">.</span><span class="na">ALIASES</span><span class="o">)</span> <span class="o">})</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">DefaultGCD</span> <span class="kd">extends</span> <span class="nc">AbstractOp</span> <span class="kd">implements</span> <span class="no">BAR</span><span class="o">.</span><span class="na">GCD</span> <span class="o">{</span> <span class="c1">// -- Inputs --</span> <span class="nd">@Parameter</span> <span class="kd">private</span> <span class="kt">double</span> <span class="n">a</span><span class="o">;</span> <span class="nd">@Parameter</span> <span class="kd">private</span> <span class="kt">double</span> <span class="n">b</span><span class="o">;</span> <span class="c1">// -- Outputs --</span> <span class="nd">@Parameter</span><span class="o">(</span><span class="n">type</span> <span class="o">=</span> <span class="nc">ItemIO</span><span class="o">.</span><span class="na">OUTPUT</span><span class="o">)</span> <span class="kd">private</span> <span class="kt">double</span> <span class="n">result</span><span class="o">;</span> <span class="nd">@Override</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="o">()</span> <span class="o">{</span> <span class="n">result</span> <span class="o">=</span> <span class="n">computeGCD</span><span class="o">(</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">);</span> <span class="o">}</span> <span class="kd">private</span> <span class="kt">double</span> <span class="nf">computeGCD</span><span class="o">(</span><span class="kd">final</span> <span class="kt">double</span> <span class="n">p1</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">double</span> <span class="n">p2</span><span class="o">)</span> <span class="o">{</span> <span class="k">return</span> <span class="n">p2</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">p1</span> <span class="o">:</span> <span class="n">computeGCD</span><span class="o">(</span><span class="n">p2</span><span class="o">,</span> <span class="n">p1</span><span class="o">%</span><span class="n">p2</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <h2 id="use-your-ops">Use your Op(s)</h2> <p>We can still use our Op through the OpService:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># @OpService ops </span> <span class="k">print</span><span class="p">(</span><span class="n">ops</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="s">"bar.gcd"</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">15</span><span class="p">))</span> </code></pre></div></div> <p>But we can also use our built-in methods:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># @bar.BAR bar </span> <span class="k">print</span><span class="p">(</span><span class="n">bar</span><span class="p">.</span><span class="n">gcd</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">15</span><span class="p">))</span> </code></pre></div></div> <p>This is especially useful in environments with code completion.</p> <p>Namespaces also present an easy way for users to find information about available functionality using the base Help ops:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># @OpService ops # @bar.BAR bar </span> <span class="c1"># Print usage for all ops in the BAR namespace </span><span class="k">print</span><span class="p">(</span><span class="n">ops</span><span class="p">.</span><span class="n">help</span><span class="p">(</span><span class="n">bar</span><span class="p">))</span> </code></pre></div></div> <h1 id="potential-next-steps">Potential next steps</h1> <h2 id="create-a-helper-service-for-your-namespace">Create a helper service for your Namespace</h2> <p>SciJava <a href="https://github.com/scijava/scijava-common/blob/scijava-common-2.47.0/src/main/java/org/scijava/service/Service.java">Services</a> are a general workhorse in a given SciJava context. There is a single instance of each Service created per context, so they are a common container for static utility style methods.</p> <p>When developing an external Namespace, an immediate benefit to creating a corresponding Service is that it provides an initialization hook for registering your new Namespace outside the Ops framework - in particular, with the SCriptService:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">bar</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.plugin.Parameter</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.plugin.Plugin</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.script.ScriptService</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.service.AbstractService</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.scijava.service.Service</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.imagej.ImageJService</span><span class="o">;</span> <span class="nd">@Plugin</span><span class="o">(</span><span class="n">type</span> <span class="o">=</span> <span class="nc">Service</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">BARService</span> <span class="kd">extends</span> <span class="nc">AbstractService</span> <span class="kd">implements</span> <span class="nc">ImageJService</span> <span class="o">{</span> <span class="nd">@Parameter</span> <span class="kd">private</span> <span class="nc">ScriptService</span> <span class="n">scriptService</span><span class="o">;</span> <span class="nd">@Override</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">initialize</span><span class="o">()</span> <span class="o">{</span> <span class="c1">// Register this namespace with the ScriptService so we can drop package prefixes</span> <span class="c1">// in script parameters, allowing:</span> <span class="c1">// @BAR</span> <span class="c1">// instead of</span> <span class="c1">// @bar.BAR</span> <span class="n">scriptService</span><span class="o">.</span><span class="na">addAlias</span><span class="o">(</span><span class="n">bar</span><span class="o">.</span><span class="na">BAR</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p><a href="https://github.com/tferr/Scripts/blob/-/BAR/src/main/java/bar/BARService.java">On GitHub</a></p> <p>Now we can drop package prefixes when using our Namespace in scripts:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># @OpService ops # @BAR bar </span> <span class="c1"># Print usage for all ops in the BAR namespace </span><span class="k">print</span><span class="p">(</span><span class="n">ops</span><span class="p">.</span><span class="n">help</span><span class="p">(</span><span class="n">bar</span><span class="p">))</span> </code></pre></div></div> <h2 id="distribute-scripts-demonstrating-how-your-ops-should-be-used">Distribute scripts demonstrating how your Ops should be used</h2> <p>The ImageJ <a href="/scripting">script editor</a> automatically collects scripts located in <code class="language-plaintext highlighter-rouge">src/main/resources/script_templates</code>. For example, if we create a file:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="o">/</span><span class="n">resources</span><span class="o">/</span><span class="n">script_templates</span><span class="o">/</span><span class="n">BAR</span><span class="o">/</span><span class="n">GCD</span><span class="p">.</span><span class="n">py</span> <span class="k">with</span> <span class="n">contents</span><span class="p">:</span> <span class="c1"># @BAR bar </span> <span class="c1"># @float a </span> <span class="c1"># @float b </span> <span class="k">print</span><span class="p">(</span><span class="s">"Greatest common divisor of "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">+</span> <span class="s">" and "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">+</span> <span class="s">" is: "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">bar</span><span class="p">.</span><span class="n">gcd</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)))</span> <span class="p">[</span><span class="n">On</span> <span class="n">GitHub</span><span class="p">](</span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">tferr</span><span class="o">/</span><span class="n">Scripts</span><span class="o">/</span><span class="n">blob</span><span class="o">/-/</span><span class="n">BAR</span><span class="o">/</span><span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="o">/</span><span class="n">resources</span><span class="o">/</span><span class="n">script_templates</span><span class="o">/</span><span class="n">BAR</span><span class="o">/</span><span class="n">GCD</span><span class="p">.</span><span class="n">py</span><span class="p">)</span> </code></pre></div></div> <p>Then users will be able to select <code class="language-plaintext highlighter-rouge">Templates > BAR > GCD</code> from the script editor window, to automatically load the script and select the correct script language (python in this case).</p> <p>This is an easy way to provide a starting point for development using your Ops.</p> <h1 id="advanced-topics">Advanced Topics</h1> <p>There are many conveniences in Op development that have not been covered in this tutorial, including:</p> <ul> <li>Create additional implementations for a given Ops interfaces <ul> <li>Specializing Ops for a variety of input types</li> </ul> </li> <li>Auto-generate your Op implementations using templates</li> <li>Write unit-tests to ensure coverage of built-in methods for your Ops</li> </ul> <p>However, all of this is done in the core <a href="https://github.com/imagej/imagej-ops/">imagej-ops</a> project and could be deduced by careful study. If you do take the time to independently attempt any of these topics, consider documenting your experience and sharing it as a tutorial on this wiki.</p> </div> </div> </section> <!-- Footer --> <section id="footer"> <ul class="icons"> <li><a href="https://forum.image.sc/tag/imagej" class="icon alt"><img src="/media/icons/image-sc.png" width="24" style="vertical-align: middle; margin-top: -10px"><span class="label">Forum</span></a></li> <li><a href="https://twitter.com/hashtag/ImageJ" class="icon brands alt fa-twitter"><span class="label">Twitter</span></a></li> <li><a href="https://github.com/imagej" class="icon brands alt fa-github"><span class="label">GitHub</span></a></li> </ul> <ul class="copyright"> <li>Design: <a href="http://html5up.net">HTML5 UP</a></li> </ul> </section> <!-- Hamburger menu --> <nav role="navigation"> <div id="ham-toggle"> <input type="checkbox" /> <span></span> <!-- top bun --> <span></span> <!-- hamburger --> <span></span> <!-- bottom bun --> <ul id="ham-menu"> <div class="menu"><h3>ImageJ Docs</h3> <ul> <li><a href="/downloads">Download</a></li> <li><details><summary>Learn</summary><ul> <li><details><summary><a href="/learn">ImageJ Basics</a></summary><ul> <li><a href="/tutorials">Tutorials</a></li> <li><a href="/learn/user-guides">User Guides</a></li> <li><a href="/learn/keyboard-shortcuts">Keyboard Shortcuts</a></li> <li><a href="/learn/tips-and-tricks">Tips and Tricks</a></li> <li><a href="/learn/troubleshooting">Troubleshooting</a></li> <li><a href="/learn/faq">Frequently Asked Questions</a></li> <li><details><summary><a href="/platforms">Supported Platforms</a></summary><ul> <li><a href="/platforms/windows">Windows</a></li> <li><a href="/platforms/macos">MacOS</a></li> <li><a href="/platforms/linux">Linux</a></li> <li><a href="/platforms/pi">Raspberry Pi</a></li> <li><a href="/platforms/android">Android</a></li> </ul></details></li> <!-- Learn/ImageJ Basics/Supported Platforms --> <li><details><summary><a href="/formats">File Formats</a></summary><ul> <li><a href="/formats/bio-formats">Bio-Formats</a></li> <li><a href="/formats/video">Video formats</a></li> <li><a href="/formats/quicktime">QuickTime</a></li> <li><a href="/formats/tiff">TIFF</a></li> <li><a href="/formats/pdf">PDF</a></li> <li><a href="/formats/dicom">DICOM</a></li> <li><a href="/formats/lsm">Zeiss LSM</a></li> <li><a href="/formats/olympus">Olympus VSI</a></li> <li><a href="/formats/lurawave">Opera Flex</a></li> <li><a href="/formats/fib-sem">FIB-SEM</a></li> </ul></details></li> <!-- Learn/ImageJ Basics/File Formats --> </ul></details></li> <!-- Learn/ImageJ --> <li><details><summary><a href="/imaging">Scientific Imaging</a></summary><ul> <li><a href="/imaging/principles">Principles of Scientific Imaging</a></li> <li><a href="/imaging/annotating-images">Annotating Images</a></li> <li><a href="/imaging/colocalization-analysis">Colocalization</a></li> <li><a href="/imaging/color-image-processing">Color Image Processing</a></li> <li><a href="/imaging/deconvolution">Deconvolution</a></li> <li><a href="/imaging/image-intensity-processing">Image Intensity Processing</a></li> <li><a href="/imaging/particle-analysis">Particle Analysis</a></li> <li><a href="/imaging/registration">Registration</a></li> <li><a href="/imaging/segmentation">Segmentation</a></li> <li><a href="/imaging/stack-slice-manipulations">Stack-slice Manipulations</a></li> <li><a href="/imaging/t-functions">T-functions</a></li> <li><a href="/imaging/tracking">Tracking</a></li> <li><a href="/imaging/visualization">Visualization</a></li> <li><a href="/imaging/z-functions">Z-functions</a></li> </ul></details></li> <!-- Learn/Scientific Imaging --> </ul></details></li> <!-- Learn --> <li><details open><summary><a href="/plugins">Extend</a></summary><ul> <li><a href="/list-of-extensions">List of Extensions</a></li> <li><details><summary><a href="/update-sites">Update Sites</a></summary><ul> <li><a href="/list-of-update-sites">List of Update Sites</a></li> <li><a href="/update-sites/following">Following an Update Site</a></li> <li><a href="/update-sites/setup">Creating an Update Site</a></li> <li><a href="/update-sites/tos">Terms of Service</a></li> <li><a href="/update-sites/automatic-uploads">Automatic Upload</a></li> <li><a href="/update-sites/core-uploads">Uploading to Core Sites</a></li> <li><a href="/update-sites/faq">Update Sites FAQ</a></li> <li><a href="/update-sites/stats">Statistics</a></li> </ul></details></li> <!-- Extend/Update Sites --> <li><details><summary><a href="/scripting">Scripting</a></summary><ul> <li><a href="/scripting/basics">Scripting Basics</a></li> <li><a href="/scripting/script-editor">Script Editor</a></li> <li><a href="/scripting/parameters">Parameters</a></li> <li><a href="/scripting/user-input">User Input</a></li> <li><a href="/scripting/auto-imports">Auto Import</a></li> <li><a href="/scripting/templates">Templates</a></li> <li><a href="/scripting/batch">Batch Processing</a></li> <li><a href="/scripting/headless">Running Headlessly</a></li> <li><a href="/scripting/comparisons">Scripting Comparisons</a></li> <li><a href="/scripting/toolbox">Toolbox</a></li> <li><details><summary>Languages</summary><ul> <li><a href="/scripting/beanshell">BeanShell Scripting</a></li> <li><a href="/scripting/groovy">Groovy Scripting</a></li> <li><a href="/scripting/macro">ImageJ Macro</a></li> <li><a href="/scripting/javascript">JavaScript</a></li> <li><a href="/scripting/clojure">Lisp (Clojure)</a></li> <li><a href="/scripting/matlab">MATLAB</a></li> <li><a href="/scripting/jython">Python (Jython)</a></li> <li><a href="/scripting/python">Python (native)</a></li> <li><a href="/scripting/renjin">R (Renjin)</a></li> <li><a href="/scripting/jruby">Ruby (JRuby)</a></li> <li><a href="/scripting/scala">Scala Scripting</a></li> </ul></details></li> <!-- Extend/Scripting/Languages --> </ul></details></li> <!-- Extend/Scripting --> <li><details open><summary><a href="/develop">Development</a></summary><ul> <li><a href="/develop/philosophy">Philosophy</a></li> <li><a href="/develop/architecture">Architecture</a></li> <li><a href="/develop/source">Source code</a></li> <li><a href="/develop/project-management">Project management</a></li> <li><a href="/develop/coding-style">Coding style</a></li> <li><a href="/develop/javadoc">Using Javadoc</a></li> <li><a href="/develop/debugging">Debugging</a></li> <li><a href="/develop/wish-list">Wish list</a></li> <li><details><summary>Tools</summary><ul> <li><a href="/develop/github">GitHub</a></li> <li><a href="/develop/maven">Maven</a></li> <li><a href="/develop/ci">CI/CD</a></li> <li><a href="/develop/dotfiles">Dotfiles</a></li> <li><details><summary><a href="/develop/ides">IDEs</a></summary><ul> <li><a href="/develop/eclipse">Eclipse</a></li> <li><a href="/develop/netbeans">NetBeans</a></li> <li><a href="/develop/intellij">IntelliJ IDEA</a></li> <li><a href="/develop/command-line">Command Line</a></li> </ul></details></li> </ul></details></li> <!-- Extend/Development/Tools --> <li><details open><summary>Guides</summary><ul> <li><a href="/develop/plugins">Writing plugins</a></li> <li><a href="/develop/improving-the-code">Contributing to a plugin</a></li> <li><a href="/develop/releasing">Development lifecycle</a></li> <li><a href="/develop/building-a-pom">Building a POM</a></li> <li><a href="/develop/debugging-exercises">Hands-on debugging</a></li> <li><a class="current-page">Adding new ops</a></li> <li><a href="/develop/formats">Adding new formats</a></li> <li><a href="/develop/native-libraries">Using native libraries</a></li> <li><a href="/develop/tips">Tips for developers</a></li> <li><a href="/develop/cpp-tips">Tips for C++ developers</a></li> <li><a href="/develop/ij1-plugins">ImageJ 1.x plugins</a></li> <li><a href="/develop/versioning">Versioning</a></li> <li><a href="/develop/logging">Logging</a></li> <li><a href="/develop/uber-jars">Uber-JARs</a></li> </ul></details></li> <!-- Extend/Development/Guides --> <li><details><summary><a href="/develop/git">Git</a></summary><ul> <li><a href="/develop/git/eclipse">Git in Eclipse (EGit)</a></li> <li><a href="/develop/git/mini-howto">Git mini howto</a></li> <li><a href="/develop/git/workshop">Git workshop</a></li> <li><a href="/develop/git/conflicts">Git conflicts</a></li> <li><a href="/develop/git/topic-branches">Git topic branches</a></li> <li><a href="/develop/git/notes">Git notes</a></li> <li><a href="/develop/git/reflogs">Git reflogs</a></li> <li><a href="/develop/git/submodules">Git submodules</a></li> <li><a href="/develop/git/pinpoint-regressions">How to pinpoint regressions</a></li> <li><a href="/develop/git/publish-a-repository">How to publish a git repository</a></li> <li><a href="/develop/git/extract-a-subproject">How to extract a subproject</a></li> </ul></details></li> <!-- Extend/Development/Git --> </ul></details></li> <!-- Extend/Development --> </ul></details></li> <!-- Extend --> <li><details><summary><a href="/contribute">Contribute</a></summary><ul> <li><a href="/contribute/citing">Citing</a></li> <li><a href="/people">Contributors</a></li> <li><a href="/orgs">Organizations</a></li> <li><a href="/contribute/governance">Governance</a></li> <li><a href="/contribute/funding">Funding</a></li> <li><a href="/contribute/fiji">Contributing to Fiji</a></li> <li><details><summary><a href="/licensing">Licensing</a></summary><ul> <li><details><summary><a href="/licensing/open-source">Open Source</a></summary><ul> <li><a href="/licensing/apache">Apache</a></li> <li><a href="/licensing/bsd">BSD</a></li> <li><a href="/licensing/epl">EPL</a></li> <li><a href="/licensing/gpl">GPL</a></li> <li><a href="/licensing/lgpl">LGPL</a></li> <li><a href="/licensing/mit">MIT</a></li> <li><a href="/licensing/public-domain">Public domain</a></li> <li><a href="/licensing/big">BIG</a></li> </ul></details></li> <!-- Contribute/Licensing/Open Source --> <li><a href="/licensing/closed-source">Proprietary</a></li> </ul></details></li> <!-- Contribute/Licensing --> <li><details><summary><a href="/editing">Editing the Wiki</a></summary><ul> <li><a href="/editing/advanced">Advanced Editing</a></li> <li><a href="/editing/buttons">Buttons</a></li> <li><a href="/editing/citations">Citations</a></li> <li><a href="/editing/code">Source Code</a></li> <li><a href="/editing/debugging">Debugging</a></li> <li><a href="/editing/headers">Headers</a></li> <li><a href="/editing/icons">Icons</a></li> <li><a href="/editing/images">Images</a></li> <li><a href="/editing/keys">Keyboard Shortcuts</a></li> <li><a href="/editing/linking">Linking</a></li> <li><a href="/editing/math">Math Expressions</a></li> <li><a href="/editing/menu-paths">Menu Paths</a></li> <li><a href="/editing/navigation">Navigation</a></li> <li><a href="/editing/notices">Notices</a></li> <li><a href="/editing/people">People</a></li> <li><a href="/editing/pitfalls">Pitfalls</a></li> <li><a href="/editing/quizzes">Quizzes</a></li> <li><a href="/editing/statbox">Statbox</a></li> <li><a href="/editing/symbols">Symbols</a></li> <li><a href="/editing/tables">Tables</a></li> <li><a href="/editing/timelines">Timelines</a></li> <li><a href="/editing/tooltips">Tooltips</a></li> <li><a href="/editing/videos">Videos</a></li> <li><a href="/editing/whitespace">Whitespace</a></li> </ul></details></li> <!-- Contribute/Editing the Wiki --> </ul></details></li> <!-- Contribute --> <li><details><summary><a href="/discuss">Discuss</a></summary><ul> <li><a href="/discuss/bugs">Reporting Issues</a></li> <li><a href="/discuss/mailing-lists">Mailing Lists</a></li> <li><a href="/discuss/chat">Chat</a></li> </ul></details></li> <!-- Discuss --> <li><details><summary>Explore</summary><ul> <li><a href="/news">News</a></li> <li><details><summary><a href="/events">Events</a></summary><ul> <li><a href="/events/presentations">Presentations</a></li> <li><a href="/events/conferences">Conferences</a></li> <li><a href="/events/hackathons">Hackathons</a></li> <li><a href="/events">More...</a></li> </ul></details></li> <!-- Discuss/Events --> <li><details><summary><a href="/libs">Libraries</a></summary><ul> <li><a href="/libs/imagej-ops">ImageJ Ops</a></li> <li><a href="/libs/imagej-common">ImageJ Common</a></li> <li><a href="/libs/imagej-legacy">ImageJ Legacy</a></li> <li><a href="/libs/scijava">SciJava</a></li> <li><a href="/libs/scifio">SCIFIO</a></li> <li><details><summary><a href="/libs/imglib2">ImgLib2</a></summary><ul> <li><a href="/libs/imglib2/getting-started">Getting Started</a></li> <li><a href="/libs/imglib2/accessors">Accessors</a></li> <li><a href="/libs/imglib2/accessibles">Accessibles</a></li> <li><a href="/libs/imglib2/examples">Examples</a></li> <li><a href="/libs/imglib2/workshop-introductory">Introductory Workshop</a></li> <li><a href="/libs/imglib2/workshop-advanced">Advanced Workshop</a></li> <li><a href="/libs/imglib2/matlab">ImgLib2 images in MATLAB</a></li> <li><a href="/libs/imglib2/benchmarks">Benchmarks</a></li> <li><a href="/libs/imglib2/faq">FAQ</a></li> <li><a href="/libs/imglib2/developing">Developing ImgLib2</a></li> <li><a href="/libs/imglib2/discussion">ImgLib2 Discussion</a></li> </ul></details></li> <!-- Explore/Libraries/ImgLib2 --> <li><a href="/libs">More...</a></li> </ul></details></li> <!-- Explore/Libraries --> <li><details><summary><a href="/software">Software</a></summary><ul> <li><a href="/software/nih-image">NIH Image</a></li> <li><a href="/software/imagej">ImageJ</a></li> <li><a href="/software/imagej2">ImageJ2</a></li> <li><a href="/software/fiji">Fiji</a></li> <li><a href="/software">More...</a></li> </ul></details></li> <!-- Explore/Software --> </ul></details></li> <!-- Explore --> </ul> </div> </ul> </div> </nav> <div id="dock-overlay-left" class="dock-overlay" data-dock-target="left-column"></div> <div id="dock-overlay-right" class="dock-overlay" data-dock-target="right-column"></div> <!-- Search results --> <div id="search-results"> <div id="search-hits"></div> <div id="pagination"></div> </div> <!-- Scripts --> <!-- Libraries --> <script src="/assets/js/jquery.min.js"></script> <script src="/assets/js/jquery.scrolly.min.js"></script> <script src="/assets/js/browser.min.js"></script> <script src="/assets/js/breakpoints.min.js"></script> <script src="/assets/js/util.js"></script> <script src="/assets/js/jquery.toc.js"></script> <script src="/assets/js/lightbox.min.js"></script> <!-- Extensions --> <!-- Site code --> <script src="/assets/js/main.js"></script> <script src="/assets/js/dock.js"></script> <script src="/assets/js/code.js"></script> <!-- Anchors --> <script src="https://cdn.jsdelivr.net/npm/anchor-js/anchor.min.js"></script> <script>anchors.add('#page h1, #page h2, #page h3, #page h4, #page h5, #page h6');</script> <!-- Citations --> <script src="https://cdn.jsdelivr.net/npm/citation-js@0.4.0-9"></script> <script src="/assets/js/cite.js"></script> <!-- Search --> <script src="https://cdn.jsdelivr.net/npm/algoliasearch@4.13.0/dist/algoliasearch-lite.umd.js"></script> <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4.40.3/dist/instantsearch.production.min.js"></script> <script src="/assets/js/search.js"></script> <script src="/assets/js/search-tweaks.js"></script> </body> </html>