CINXE.COM
Developing using native libraries
<!DOCTYPE html> <html> <head> <title>Developing using native libraries</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="Developing using native libraries" 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/native-libraries" 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/native-libraries.md">Page history</a> <a href="https://github.com/imagej/imagej.github.io/edit/main/_pages/develop/native-libraries.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 href="/develop/writing-ops">Adding new ops</a></li> <li><a href="/develop/formats">Adding new formats</a></li> <li><a class="current-page">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>Developing using native libraries</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"> <div class="notice" style="font-size: 2; background: #ffcccb; border-left: 10px solid #f57900"><div class="notice-icon"><img src="/media/icons/warning.png" /></div><div class="notice-content"><p>This section is out of date, potentially misleading or invalid. Be careful with any instructions here. When in doubt, <a href="/discuss">ask for help from the community</a>.</p> </div> </div> <h1 id="introduction">Introduction</h1> <p>Sometimes, you may want to use 3rd party libraries that are not available as Java components, but only as native libraries.</p> <p>There are two options available to make use of native libraries: <a href="http://jna.java.net/">JNA</a> and JNI (see below for detailed descriptions).</p> <h2 id="disadvantages-of-using-native-libraries">Disadvantages of using native libraries</h2> <p>Even if JNA and JNI provide some convenience for using native libraries, there are substantial downsides of using native libraries:</p> <ul> <li>Using native libraries flies in the face of the platform independence of Java</li> </ul> <p>Even if ImageJ only supports 32-bit/64-bit Windows, macOS and Linux (and PowerPC with macOS for the time being), it is a major hassle to maintain them. It also means that you incur the problems with C/C++ where a library compiling successfully on one platform does not at all imply that it compiles on any other platform. There are even examples of C code compiling fine for 32-bit but not for 64-bit CPUs on the very same Operating system.</p> <ul> <li>No “Compile once, run everywhere”</li> </ul> <p>It is one of Java’s greatest strengths that you do not need to compile for every platform you plan (or anyone else plans) to run on. Native libraries take away that advantage.</p> <ul> <li>By using native libraries, it is much easier to produce fatal errors that tear down the complete Java virtual machine. Consequently, debugging can be really hard when using native libraries.</li> </ul> <p>For further arguments to use Java instead of native libraries, see also our <a href="/develop/philosophy#why-java">rationale for using Java</a>.</p> <h2 id="jna-vs-jni">JNA vs JNI</h2> <p>The benefits of JNA over JNI are:</p> <ul> <li>scriptable</li> <li>you do not need a C compiler</li> <li>a native library can be dropped in for an additional platform without any recompilation</li> </ul> <p>The benefits of JNI over JNA are:</p> <ul> <li>official part of Java</li> <li>way faster</li> <li>JNI is “type-safer” (i.e. Java and native code access data via the same type definitions)</li> </ul> <h1 id="jna">JNA</h1> <p>The <a href="http://jna.java.net/">JNA project</a> (<em>Java Native Access</em>) tries to provide an easy, pure-Java way to access native libraries using their native interface.</p> <h2 id="functions">Functions</h2> <p>To this end, the developer has to define an interface describing in Java terms what functions the library provides. Example:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">com.sun.jna.Library</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">interface</span> <span class="nc">C</span> <span class="kd">extends</span> <span class="nc">Library</span> <span class="o">{</span> <span class="kd">public</span> <span class="kt">int</span> <span class="nf">symlink</span><span class="o">(</span><span class="nc">String</span> <span class="n">oldpath</span><span class="o">,</span> <span class="nc">String</span> <span class="n">newpath</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Note:</p> <ul> <li>Even if the package name is <code class="language-plaintext highlighter-rouge">com.sun.jna</code>, JNA is not an official part of Java. As a consequence, JNA supports less platforms than official Java itself.</li> <li>You do not need to declare all the functions offered by the native library. In this example, only <code class="language-plaintext highlighter-rouge">symlink</code> was declared.</li> <li>The Java type <code class="language-plaintext highlighter-rouge">String</code> is mapped to <code class="language-plaintext highlighter-rouge">const char *</code> in the C layer. The same happens for other primitive Java types.</li> <li>Since the parameters need to be mapped prior to calling the native function, and mapped back after it returns, and all this mapping is done using reflection, JNA is relatively slow compared to JNI (except when the amount of time spent copying data is outweighed by the processing time spent within the native library).</li> <li>There is no guarantee by the compiler that the interface is correct. In fact, you can declare the functions incorrectly very easily, which results in hard crashes of the Java virtual machine.</li> <li>Note: to define this interface in <a href="/scripting/beanshell">BeanShell</a>, you need to use the syntax <code class="language-plaintext highlighter-rouge">interface C implements Library</code> instead of employing the keyword <code class="language-plaintext highlighter-rouge">extends</code>.</li> </ul> <p>Use the library in this way:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">com.sun.jna.Native</span><span class="o">;</span> <span class="no">C</span> <span class="n">c</span> <span class="o">=</span> <span class="o">(</span><span class="no">C</span><span class="o">)</span><span class="nc">Native</span><span class="o">.</span><span class="na">loadLibrary</span><span class="o">(</span><span class="s">"c"</span><span class="o">,</span> <span class="no">C</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> <span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="na">symlink</span><span class="o">(</span><span class="n">source</span><span class="o">,</span> <span class="n">target</span><span class="o">);</span> </code></pre></div></div> <h3 id="specifying-library-search-paths">Specifying library search paths</h3> <p>If you want to use a library that is not installed in one of the locations your platform looks for libraries by default, you may need to tell JNA where to find the library:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">NativeLibrary</span><span class="o">.</span><span class="na">addSearchPath</span><span class="o">(</span><span class="s">"opencv"</span><span class="o">,</span> <span class="s">"C:\\opencv"</span><span class="o">);</span> <span class="nc">OpenCV</span> <span class="n">openCV</span> <span class="o">=</span> <span class="o">(</span><span class="nc">OpenCV</span><span class="o">)</span><span class="nc">NativeLibrary</span><span class="o">.</span><span class="na">loadLibrary</span><span class="o">(</span><span class="s">"opencv"</span><span class="o">,</span> <span class="nc">OpenCV</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> </code></pre></div></div> <p>Note: some libraries depend on other libraries. If the dependencies are not in the default library path, it might be not possible to load them from within Java without restarting the virtual machine, depending on the platform. On Linux, e.g. you would need to set the environment variable <code class="language-plaintext highlighter-rouge">LD_LIBRARY_PATH</code> accordingly (setting them in the Java process does not help, as the dynamic loader was already initialized and does not respect a change in that variable after initialization).</p> <h3 id="constantsenums">Constants/enums</h3> <p>If the C header defines constants using the <code class="language-plaintext highlighter-rouge">#define</code> statement, the constant is nowhere to be found in the compiled native library. Likewise, the C compiler optimizes out the names of enums. Therefore, both constants and enums need to be defined in the interface.</p> <p>For example, this C header:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#ifndef MY_HEADER_H #define MY_HEADER_H </span> <span class="cp">#define OFF 0 #define ON 0xff </span> <span class="k">enum</span> <span class="n">counter_t</span> <span class="p">{</span> <span class="n">ZERO</span><span class="p">,</span> <span class="n">ONE</span><span class="p">,</span> <span class="n">TWO</span><span class="p">,</span> <span class="n">THREE</span> <span class="p">};</span> <span class="k">extern</span> <span class="n">counter_t</span> <span class="nf">get_counter</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> <span class="cp">#endif </span></code></pre></div></div> <p>would need to be handled with a JNA-based interface like this one:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">MyLibrary</span> <span class="kd">extends</span> <span class="nc">Library</span> <span class="o">{</span> <span class="kd">public</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">OFF</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">ON</span> <span class="o">=</span> <span class="mh">0xff</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">ZERO</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">ONE</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">TWO</span> <span class="o">=</span> <span class="mi">2</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">THREE</span> <span class="o">=</span> <span class="mi">3</span><span class="o">;</span> <span class="kd">public</span> <span class="kt">int</span> <span class="nf">get_counter</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <h3 id="structures">Structures</h3> <p>Some functions do not take simple data types as parameters, but so-called <em>structs</em>. These have to be defined as inner static classes of the interface, and they need to extend the class <code class="language-plaintext highlighter-rouge">com.sun.jna.Structure</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">com.sun.jna.Library</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">com.sun.jna.Structure</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">interface</span> <span class="nc">C</span> <span class="kd">extends</span> <span class="nc">Library</span> <span class="o">{</span> <span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">timeval</span> <span class="kd">implements</span> <span class="nc">Structure</span> <span class="o">{</span> <span class="kt">long</span> <span class="n">tv_sec</span><span class="o">,</span> <span class="n">tv_usec</span><span class="o">;</span> <span class="o">}</span> <span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">timezeone</span> <span class="kd">implements</span> <span class="nc">Structure</span> <span class="o">{</span> <span class="kt">int</span> <span class="n">tz_minuteswest</span><span class="o">,</span> <span class="n">tz_dsttime</span><span class="o">;</span> <span class="o">}</span> <span class="kd">public</span> <span class="kt">int</span> <span class="nf">gettimeofday</span><span class="o">(</span><span class="n">timeval</span> <span class="n">timeval</span><span class="o">,</span> <span class="n">timezone</span> <span class="n">timezone</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Some fields of the structures might be fixed-size arrays (e.g. <code class="language-plaintext highlighter-rouge">unsigned char path[1024]</code>). These fields should be declared with default initializers in Java (e.g. <code class="language-plaintext highlighter-rouge">byte[] path = new byte[1024];</code>).</p> <h4 id="accessing-structures-via-pointers">Accessing structures via pointers</h4> <p>A function you call may return a pointer to a structure. To initialize the fields of a Java version of such a structure, you can use the <code class="language-plaintext highlighter-rouge">useMemory(Pointer)</code> and <code class="language-plaintext highlighter-rouge">read()</code> methods:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">...</span> <span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">MyStruct</span> <span class="o">{</span> <span class="kd">public</span> <span class="nf">MyStruct</span><span class="o">(</span><span class="nc">Pointer</span> <span class="n">p</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// cannot use super(p) because of fixed-size array fields</span> <span class="kd">super</span><span class="o">();</span> <span class="n">useMemory</span><span class="o">(</span><span class="n">p</span><span class="o">);</span> <span class="c1">// set pointer</span> <span class="n">read</span><span class="o">();</span> <span class="c1">// initialize fields</span> <span class="o">}</span> <span class="kd">public</span> <span class="nf">MyStruct</span><span class="o">()</span> <span class="o">{</span> <span class="kd">super</span><span class="o">();</span> <span class="c1">// handle fixed-size array fields correctly</span> <span class="n">ensureAllocated</span><span class="o">();</span> <span class="o">}</span> <span class="o">}</span> <span class="o">...</span> </code></pre></div></div> <p>Note: when the superclass’ constructor is called, the fixed-size array fields are not yet initialized. Therefore, the superclass’ constructor has no way to handle them correctly: their size is not known. That is the reason why you have to call <code class="language-plaintext highlighter-rouge">ensureAllocated()</code> and why you cannot use the superclass’ <code class="language-plaintext highlighter-rouge">super(Pointer)</code> constructor. Technically, when your struct does not contain fixed-size array fields, you can, but getting used to always avoid the <code class="language-plaintext highlighter-rouge">super(Pointer)</code> constructor will help you stay out of trouble.</p> <h3 id="passing-structures-by-value">Passing structures by value</h3> <p>When passing instances of a Structure to a function, memory is allocated and written to automatically, and a pointer is passed.</p> <p>If you want to pass a Structure by value instead, you have to subclass it and implement the <code class="language-plaintext highlighter-rouge">Structure.ByValue</code> interface. This interface is purely a tag, and does not require any additional functions to be defined.</p> <p>Example:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Timespec</span> <span class="kd">extends</span> <span class="nc">Structure</span> <span class="o">{</span> <span class="kt">long</span> <span class="n">tv_sec</span><span class="o">;</span> <span class="kt">long</span> <span class="n">tv_usec</span><span class="o">;</span> <span class="o">}</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">Stat</span> <span class="kd">extends</span> <span class="nc">Structure</span> <span class="o">{</span> <span class="kt">long</span> <span class="cm">/* dev_t */</span> <span class="n">st_dev</span><span class="o">;</span> <span class="cm">/* ID of device containing file */</span> <span class="kt">long</span> <span class="cm">/* ino_t */</span> <span class="n">st_ino</span><span class="o">;</span> <span class="cm">/* inode number */</span> <span class="kt">long</span> <span class="cm">/* nlink_t */</span> <span class="n">st_nlink</span><span class="o">;</span> <span class="cm">/* number of hard links */</span> <span class="kt">int</span> <span class="cm">/* mode_t */</span> <span class="n">st_mode</span><span class="o">;</span> <span class="cm">/* protection */</span> <span class="kt">int</span> <span class="cm">/* uid_t */</span> <span class="n">st_uid</span><span class="o">;</span> <span class="cm">/* user ID of owner */</span> <span class="kt">int</span> <span class="cm">/* gid_t */</span> <span class="n">st_gid</span><span class="o">;</span> <span class="cm">/* group ID of owner */</span> <span class="kt">int</span> <span class="n">__pad0</span><span class="o">;</span> <span class="kt">long</span> <span class="cm">/* dev_t */</span> <span class="n">st_rdev</span><span class="o">;</span> <span class="cm">/* device ID (if special file) */</span> <span class="kt">long</span> <span class="cm">/* off_t */</span> <span class="n">st_size</span><span class="o">;</span> <span class="cm">/* total size, in bytes */</span> <span class="kt">long</span> <span class="cm">/* blksize_t */</span> <span class="n">st_blksize</span><span class="o">;</span> <span class="cm">/* blocksize for file system I/O */</span> <span class="kt">int</span> <span class="cm">/* blkcnt_t */</span> <span class="n">st_blocks</span><span class="o">;</span> <span class="cm">/* number of 512B blocks allocated */</span> <span class="nc">Timespec</span> <span class="cm">/* time_t */</span> <span class="n">st_atime</span><span class="o">;</span> <span class="cm">/* time of last access */</span> <span class="nc">Timespec</span> <span class="cm">/* time_t */</span> <span class="n">st_mtime</span><span class="o">;</span> <span class="cm">/* time of last modification */</span> <span class="nc">Timespec</span> <span class="cm">/* time_t */</span> <span class="n">st_ctime</span><span class="o">;</span> <span class="cm">/* time of last status change */</span> <span class="o">}</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">StatByValue</span> <span class="kd">extends</span> <span class="nc">Stat</span> <span class="kd">implements</span> <span class="nc">Structure</span><span class="o">.</span><span class="na">ByValue</span> <span class="o">{</span> <span class="kd">public</span> <span class="nf">StatByValue</span><span class="o">(</span><span class="nc">Stat</span> <span class="n">stat</span><span class="o">)</span> <span class="o">{</span> <span class="kd">super</span><span class="o">();</span> <span class="n">ensureAllocated</span><span class="o">();</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">buffer</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">byte</span><span class="o">[</span><span class="n">size</span><span class="o">()];</span> <span class="n">stat</span><span class="o">.</span><span class="na">getPointer</span><span class="o">().</span><span class="na">read</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">buffer</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">buffer</span><span class="o">.</span><span class="na">length</span><span class="o">);</span> <span class="n">getPointer</span><span class="o">().</span><span class="na">write</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">buffer</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">buffer</span><span class="o">.</span><span class="na">length</span><span class="o">);</span> <span class="n">read</span><span class="o">();</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <h2 id="scripting-jna">Scripting JNA</h2> <p>In <a href="/scripting/beanshell">BeanShell</a>, it is not possible to extend interfaces, so it is not possible to imitate the plain Java way to use JNA. Other scripting languages have similar problems as far as JNA is concerned.</p> <p>But you can use the <code class="language-plaintext highlighter-rouge">getFunction(String)</code> method of <code class="language-plaintext highlighter-rouge">NativeLibrary</code> to get a function object, whose methods <code class="language-plaintext highlighter-rouge">invokeInt(Object[])</code>, <code class="language-plaintext highlighter-rouge">invokePointer(Object[])</code> and friends will allow you to call the function.</p> <p>If the result is not a basic type, you can use <code class="language-plaintext highlighter-rouge">Pointer</code>’s methods to access the data. BeanShell example:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">com.sun.jna.NativeLibrary</span><span class="o">;</span> <span class="c1">// get the C runtime library</span> <span class="n">c</span> <span class="o">=</span> <span class="nc">NativeLibrary</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"c"</span><span class="o">);</span> <span class="c1">// retrieve the getenv() function and call it</span> <span class="n">getenv</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="na">getFunction</span><span class="o">(</span><span class="s">"getenv"</span><span class="o">);</span> <span class="n">print</span><span class="o">(</span><span class="n">getenv</span><span class="o">.</span><span class="na">invokePointer</span><span class="o">(</span><span class="k">new</span> <span class="nc">Object</span><span class="o">[]</span> <span class="o">{</span> <span class="s">"HELLO"</span> <span class="o">}).</span><span class="na">getString</span><span class="o">(</span><span class="mi">0</span><span class="o">));</span> <span class="c1">// retrieve and use the setenv() function</span> <span class="n">setenv</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="na">getFunction</span><span class="o">(</span><span class="s">"setenv"</span><span class="o">);</span> <span class="n">print</span><span class="o">(</span><span class="n">setenv</span><span class="o">.</span><span class="na">invokeInt</span><span class="o">(</span><span class="k">new</span> <span class="nc">Object</span><span class="o">[]</span> <span class="o">{</span> <span class="s">"HELLO"</span><span class="o">,</span> <span class="s">"world"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">Integer</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="o">}));</span> <span class="c1">// show that it did something</span> <span class="n">print</span><span class="o">(</span><span class="n">getenv</span><span class="o">.</span><span class="na">invokePointer</span><span class="o">(</span><span class="k">new</span> <span class="nc">Object</span><span class="o">[]</span> <span class="o">{</span> <span class="s">"HELLO"</span> <span class="o">}).</span><span class="na">getString</span><span class="o">(</span><span class="mi">0</span><span class="o">));</span> <span class="c1">// note that System.getenv() remains oblivious</span> <span class="n">print</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">getenv</span><span class="o">(</span><span class="s">"HELLO"</span><span class="o">));</span> </code></pre></div></div> <p>There can be substantial complications: some function names do not actually refer to functions in the native library, but are redirected to another function by the preprocessor. Example: at least on Linux, <code class="language-plaintext highlighter-rouge">lstat()</code> actually calls <code class="language-plaintext highlighter-rouge">__lxstat()</code> with additional parameters.</p> <p>Also, the classes defined in your scripting language of choice might not be applicable for use with JNA. BeanShell, for one, adds two fields that JNA cannot (and should not) handle. As a workaround, you can use <code class="language-plaintext highlighter-rouge">Pointer</code>’s <code class="language-plaintext highlighter-rouge">get</code> family of methods.</p> <p>Example:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">com.sun.jna.Memory</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">com.sun.jna.NativeLibrary</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">java.util.Date</span><span class="o">;</span> <span class="n">c</span> <span class="o">=</span> <span class="nc">NativeLibrary</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"c"</span><span class="o">);</span> <span class="n">lstat</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="na">getFunction</span><span class="o">(</span><span class="s">"__lxstat"</span><span class="o">);</span> <span class="n">errno</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="na">getFunction</span><span class="o">(</span><span class="s">"errno"</span><span class="o">);</span> <span class="n">path</span> <span class="o">=</span> <span class="nc">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"imagej.dir"</span><span class="o">);</span> <span class="n">print</span><span class="o">(</span><span class="n">path</span><span class="o">);</span> <span class="n">stat</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Memory</span><span class="o">(</span><span class="mi">144</span><span class="o">);</span> <span class="n">result</span> <span class="o">=</span> <span class="n">lstat</span><span class="o">.</span><span class="na">invokeInt</span><span class="o">(</span><span class="k">new</span> <span class="nc">Object</span><span class="o">[]</span> <span class="o">{</span> <span class="k">new</span> <span class="nc">Integer</span><span class="o">(</span><span class="mi">0</span><span class="o">),</span> <span class="n">path</span><span class="o">,</span> <span class="n">stat</span> <span class="o">});</span> <span class="n">print</span><span class="o">(</span><span class="s">"result: "</span> <span class="o">+</span> <span class="n">result</span><span class="o">);</span> <span class="k">if</span> <span class="o">(</span><span class="n">result</span> <span class="o"><</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span> <span class="n">strerror</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="na">getFunction</span><span class="o">(</span><span class="s">"strerror"</span><span class="o">);</span> <span class="n">err</span> <span class="o">=</span> <span class="n">errno</span><span class="o">.</span><span class="na">getInt</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span> <span class="n">error</span> <span class="o">=</span> <span class="n">strerror</span><span class="o">.</span><span class="na">invokePointer</span><span class="o">(</span><span class="k">new</span> <span class="nc">Object</span><span class="o">[]</span> <span class="o">{</span> <span class="k">new</span> <span class="nc">Integer</span><span class="o">(</span><span class="n">err</span><span class="o">)</span> <span class="o">}).</span><span class="na">getString</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span> <span class="n">print</span><span class="o">(</span><span class="s">"errno: "</span> <span class="o">+</span> <span class="n">error</span> <span class="o">+</span> <span class="s">" ("</span> <span class="o">+</span> <span class="n">err</span> <span class="o">+</span> <span class="s">")"</span><span class="o">);</span> <span class="o">}</span> <span class="n">print</span><span class="o">(</span><span class="s">"blocks: "</span> <span class="o">+</span> <span class="n">stat</span><span class="o">.</span><span class="na">getInt</span><span class="o">(</span><span class="mi">64</span><span class="o">));</span> <span class="n">print</span><span class="o">(</span><span class="s">"atime: "</span> <span class="o">+</span> <span class="k">new</span> <span class="nc">Date</span><span class="o">(</span><span class="n">stat</span><span class="o">.</span><span class="na">getLong</span><span class="o">(</span><span class="mi">72</span><span class="o">)</span> <span class="o">*</span> <span class="mi">1000</span><span class="o">));</span> <span class="n">print</span><span class="o">(</span><span class="s">"mtime: "</span> <span class="o">+</span> <span class="k">new</span> <span class="nc">Date</span><span class="o">(</span><span class="n">stat</span><span class="o">.</span><span class="na">getLong</span><span class="o">(</span><span class="mi">88</span><span class="o">)</span> <span class="o">*</span> <span class="mi">1000</span><span class="o">));</span> <span class="n">print</span><span class="o">(</span><span class="s">"ctime: "</span> <span class="o">+</span> <span class="k">new</span> <span class="nc">Date</span><span class="o">(</span><span class="n">stat</span><span class="o">.</span><span class="na">getLong</span><span class="o">(</span><span class="mi">104</span><span class="o">)</span> <span class="o">*</span> <span class="mi">1000</span><span class="o">));</span> </code></pre></div></div> <h1 id="jni">JNI</h1> <p>The abbreviation <em>JNI</em> stands for <em>Java Native Interface</em>. It is the original and best supported way to access native libraries from within Java. As such, it is robust but also a bit cumbersome to use.</p> <h2 id="first-steps">First steps</h2> <p>Before implementing any native (C or C++) code, you need to declare a native function. Example:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Hello_World_JNI</span> <span class="o">{</span> <span class="kd">public</span> <span class="kd">native</span> <span class="kt">void</span> <span class="nf">helloWorld</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <p>This tells the JVM that the method <code class="language-plaintext highlighter-rouge">helloWorld()</code> is implemented in a native library (which has to be loaded separately).</p> <p>The next step is to generate a C header with the declaration of the C function implementing that method:</p> <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>javac Hello_World_JNI.java javah <span class="nt">-classpath</span> <span class="nb">.</span> Hello_World_JNI </code></pre></div></div> <p>Note that the executable <code class="language-plaintext highlighter-rouge">javah</code> works on <code class="language-plaintext highlighter-rouge">.class</code> files only, hence we have to compile the <code class="language-plaintext highlighter-rouge">.java</code> source file first. The output is a <code class="language-plaintext highlighter-rouge">.h</code> file.</p> <p>After this, the code doing the actual work needs to be implemented in a separate <code class="language-plaintext highlighter-rouge">.c</code> file. This should include the header file generated by <code class="language-plaintext highlighter-rouge">javah</code> and be compiled to a shared library: <code class="language-plaintext highlighter-rouge">.dll</code> on Windows, <code class="language-plaintext highlighter-rouge">.dylib</code> on macOS (Apple’s Java also used the extension <code class="language-plaintext highlighter-rouge">.jnilib</code>), and <code class="language-plaintext highlighter-rouge">.so</code> everywhere else.</p> <p>Before the native method can be called, the JVM needs to load the native library. There are basically two different methods to do that, <code class="language-plaintext highlighter-rouge">System.loadLibrary()</code> and <code class="language-plaintext highlighter-rouge">System.load()</code>. The former looks for the library in the system-wide library search path while the latter expects an absolute path to the dynamic link library file. For the purposes of ImageJ, the latter is usually preferred because we want to avoid requiring administrator privileges of our users.</p> <h2 id="support-in-imagej">Support in ImageJ</h2> <p>Native libraries located in:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><ImageJ-directory>/lib/<platform>/ </code></pre></div></div> <p>will automatically be added to the <code class="language-plaintext highlighter-rouge">java.library.path</code>, exposing them in Java land - where they still need to be loaded. One option for loading is to create a <code class="language-plaintext highlighter-rouge">Service</code> that loads the native library in its <code class="language-plaintext highlighter-rouge">initialize()</code> method. For example, see the <a href="https://github.com/imagej/imagej-itk/blob/imagej-itk-0.1.0/src/main/java/net/imagej/itk/DefaultImageJItkService.java#L84-L91">ITK compatibility layer</a>.</p> <p>The Fiji build system also supports native targets by compiling source files whose names end in <code class="language-plaintext highlighter-rouge">.c</code> using gcc. If C sources are found, javah will be called and a native library will be compiled using GCC and the resulting shared library will be put into the <code class="language-plaintext highlighter-rouge"><fiji-directory>/lib/<platform>/</code> directory.</p> <p>Finally, the <code class="language-plaintext highlighter-rouge">fiji.JNI</code> class in <code class="language-plaintext highlighter-rouge">fiji-lib.jar</code> provides convenience methods to load native libraries. Example:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">static</span> <span class="o">{</span> <span class="no">JNI</span><span class="o">.</span><span class="na">loadLibrary</span><span class="o">(</span><span class="s">"hello-world"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <h2 id="using-the-java-native-interface-from-c">Using the Java Native Interface from C</h2> <p>There are a couple of things one needs to keep in mind when accessing Java classes, instances and methods from C.</p> <p>The most important is: Java has its own memory management. In contrast to C, it moves things around when needed. In C, once you have obtained an address to some data, it is the programmer’s duty to make sure that the memory range is valid until no variables hold any references (addresses) to that range any longer. To access data stored in the Java Virtual Machine’s memory range (the <em>heap</em>), one has to <em>pin</em> those data to a certain memory location and tell the JVM when it is free to move the data again.</p> <p>Such pinning issues are the nastiest things when working with JNI since it is all too easy to come up with sloppy code that just works by chance during the testing phase.</p> <p>Every call from Java to a native function passes as first parameter a reference to the JNI environment. This is an opaque pointer to internal state variables that are required for literally every interaction with Java. Example:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">JNIEXPORT</span> <span class="kt">void</span> <span class="n">JNICALL</span> <span class="nf">Java_Hello_1World_helloWorld</span> <span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jclass</span> <span class="n">object</span><span class="p">,</span> <span class="n">jstring</span> <span class="n">message</span><span class="p">);</span> </code></pre></div></div> <p>Typically, you will work a lot with primitive types that are available under the names <code class="language-plaintext highlighter-rouge">jbyte</code>, <code class="language-plaintext highlighter-rouge">jshort</code>, <code class="language-plaintext highlighter-rouge">jint</code>, <code class="language-plaintext highlighter-rouge">jlong</code>, etc. These are usually identical with the native C types <code class="language-plaintext highlighter-rouge">char</code>, <code class="language-plaintext highlighter-rouge">short</code>, <code class="language-plaintext highlighter-rouge">int</code>, <code class="language-plaintext highlighter-rouge">long</code> (but not always; the devil is in the cross-platform details, as always).</p> <p>One notable exception is <code class="language-plaintext highlighter-rouge">jchar</code> which is <em>not</em> identical to <code class="language-plaintext highlighter-rouge">char</code>. The authors of Unix decided in their infinite wisdom that you will only ever need 7 bits, or at most 8 bits, to encode text. The authors of Java knew that this is wrong and therefore <code class="language-plaintext highlighter-rouge">jchar</code> refers to 16-bit Unicode characters. In C, you will typically work with UTF-8 (for convenience and to save memory), so make sure you use the <code class="language-plaintext highlighter-rouge">*UTF</code> functions of the JNI API (e.g. <code class="language-plaintext highlighter-rouge">NewStringUTF()</code> instead of <code class="language-plaintext highlighter-rouge">NewString()</code>).</p> <h3 id="calling-the-jni-api">Calling the JNI API</h3> <p>There are many functions in the JNI API, and almost all of them are stored as function pointers in the <code class="language-plaintext highlighter-rouge">JNIEnv</code> instance. Since many of them need to access the environment to interact with state variables hidden from the user, most calls look like this, passing the environment as first parameter back to the function:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-></span><span class="n">NameOfTheFunction</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="p">...);</span> </code></pre></div></div> <h3 id="calling-methods-and-accessing-fields">Calling methods and accessing fields</h3> <p>If you need to call a Java method from C, you first need a reference to the class. Note: the class name must be passed in UTF-8 and in the <em>slashed</em> format rather than the dotted one. Example:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">jclass</span> <span class="n">image_plus_class</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-></span><span class="n">FindClass</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="s">"ij/ImagePlus"</span><span class="p">);</span> </code></pre></div></div> <p>Primitive types do not have corresponding <code class="language-plaintext highlighter-rouge">jclass</code> instances, there are individual accessors for every primitive type where applicable.</p> <p>Should you need to access arrays, prefix the class name with an opening square bracket, e.g. “[ij/process/ImageProcessor”;</p> <p>Arrays of primitive types are special: the “class names” are upper-case letters such as <code class="language-plaintext highlighter-rouge">B</code> for <code class="language-plaintext highlighter-rouge">byte</code>, <code class="language-plaintext highlighter-rouge">I</code> for <code class="language-plaintext highlighter-rouge">int</code> and (funnily enough) <code class="language-plaintext highlighter-rouge">Z</code> for <code class="language-plaintext highlighter-rouge">boolean</code>. The corresponding array’s class name is then <code class="language-plaintext highlighter-rouge">[B</code>, <code class="language-plaintext highlighter-rouge">[I</code> and <code class="language-plaintext highlighter-rouge">[Z</code>.</p> <p>The easiest way to determine the class name is to instantiate the class in Java and call <code class="language-plaintext highlighter-rouge">instance.getClass().getName()</code> on the instance.</p> <p>To call a method you need to obtain the method id first:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">jmethodID</span> <span class="n">get_title_method</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-></span><span class="n">GetMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">image_plus_class</span><span class="p">,</span> <span class="s">"getTitle"</span><span class="p">,</span> <span class="s">"Ljava/lang/String;()"</span><span class="p">);</span> </code></pre></div></div> <p>The fourth parameter is the <em>signature</em> specifying the input parameters’ and the return value’s types. The easiest way to find out what the exact signature is, is to call <code class="language-plaintext highlighter-rouge">javap</code> on the class, passing the <code class="language-plaintext highlighter-rouge">-s</code> option to show the signatures in addition to the human-digestable information.</p> <p>Once you have the method id, you can call the method, passing an instance of the corresponding class:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-></span><span class="n">CallVoidMethod</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">instance</span><span class="p">,</span> <span class="n">image</span><span class="p">,</span> <span class="n">get_title_method</span><span class="p">);</span> </code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">Call<return-type>Method()</code> family of functions take a variable number of arguments. Be very careful to pass the correct number and types of parameters!</p> <h3 id="some-tips">Some tips</h3> <ul> <li> <p>Never assume that the reference to a method, or even the <code class="language-plaintext highlighter-rouge">JNIEnv</code> parameter are constant between calls to native functions. A very likely source for segmentation faults/access violations that take the complete JVM down.</p> </li> <li> <p>Always make sure that you release the memory accessed via JNI as soon as possible. This avoids not only memory leaks but also performance issues due to preventing the JVM’s memory management to do its thing.</p> </li> <li> <p>For performance, you should minimize the use of <code class="language-plaintext highlighter-rouge">FindClass()</code> and <code class="language-plaintext highlighter-rouge">GetMethodID()</code>: while Java 7 promises better performance for these functions, still a lot of people work with Java 5 or Java 6 where such calls are slow.</p> </li> <li> <p>Pay attention to the compiler’s warnings. They are not there just for fun.</p> </li> </ul> <h2 id="caveats">Caveats</h2> <p>The most important issue is that you should know which platforms (combination of Operating System and architecture, i.e. <code class="language-plaintext highlighter-rouge">i386 Windows</code> and <code class="language-plaintext highlighter-rouge">x86_64 Windows</code> are different) you need to support and make sure that the native libraries are present. Otherwise your users will see a lot of unhelpful <code class="language-plaintext highlighter-rouge">UnsatisfiedLinkError</code> exceptions.</p> <p>Usually, you should not need to worry about these issues, as Fiji hides them conveniently from you (this is one of Fiji’s mission, to hide unnecessarily and annoyingly tedious details).</p> <ul> <li> <p>The C source needs to be compiled with the <code class="language-plaintext highlighter-rouge">_JNI_IMPLEMENTATION_</code> symbol defined. This is due to Windows which requires <code class="language-plaintext highlighter-rouge">.dll</code> files to mark explicitly which symbols are to be offered by the library and which ones need to be imported from another library.</p> </li> <li> <p>On Windows, symbols are auto-versioned by default. This interfers with constant names required by JNI. Therefore, you need to compile C sources with the GCC linker option <code class="language-plaintext highlighter-rouge">-kill-at</code>. If you ask GCC to link for you, you need to pass that option as <code class="language-plaintext highlighter-rouge">-Wl,-kill-at</code>.</p> </li> <li> <p>The java property <code class="language-plaintext highlighter-rouge">java.library.path</code> needs to be set to the path where the <code class="language-plaintext highlighter-rouge">.so</code>, <code class="language-plaintext highlighter-rouge">.dylib/.jnilib</code> or <code class="language-plaintext highlighter-rouge">.dll</code> files can be found (for Linux/BSD/Haiku/etc, macOS and Windows, respectively).</p> </li> <li> <p>Additionally to the <code class="language-plaintext highlighter-rouge">java.library.path</code> property, the environment variable <code class="language-plaintext highlighter-rouge">LD_LIBRARY_PATH</code>, <code class="language-plaintext highlighter-rouge">DYLD_LIBRARY_PATH</code> or <code class="language-plaintext highlighter-rouge">PATH</code> should be adjusted accordingly on Linux/BSD/Haiku/etc, macOS and Windows, respectively.</p> </li> <li> <p>If you need to load not only one library, but that library needs to load yet another library, you should set the search path so that the dynamic linker looks in the same directory as the original library, to avoid having to adjust the system-wide search path (which requires administrator privileges). The GCC linker option is called <code class="language-plaintext highlighter-rouge">-R$ORIGIN/</code> (note that you must prevent the command-line from expanding the <code class="language-plaintext highlighter-rouge">$</code> character).</p> </li> </ul> <h2 id="further-reading">Further reading</h2> <p>For full information on JNI, see <a href="http://java.sun.com/docs/books/jni/html/jniTOC.html">Sun’s/Oracle’s programmer guide on JNI</a>.</p> <h1 id="quick-reference">Quick reference</h1> <p>This page lists some hints on working with native libraries in the different environments supported by ImageJ.</p> <table> <thead> <tr> <th>Action</th> <th>Linux</th> <th>macOS</th> <th>Windows</th> </tr> </thead> <tbody> <tr> <td>List dependencies of libraries</td> <td><code class="language-plaintext highlighter-rouge">ldd <library-file></code></td> <td><code class="language-plaintext highlighter-rouge">otool -L <library-file></code></td> <td><code class="language-plaintext highlighter-rouge">objdump -p <library-file> | grep "DLL Name:"</code></td> </tr> <tr> <td>Trace system calls</td> <td><code class="language-plaintext highlighter-rouge">strace -Ffo syscall.log ./fiji <args></code></td> <td><code class="language-plaintext highlighter-rouge">dtruss ./fiji <args></code></td> <td>Use <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/procmon">Sysinternal’s Process Monitor</a></td> </tr> </tbody> </table> </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 href="/develop/writing-ops">Adding new ops</a></li> <li><a href="/develop/formats">Adding new formats</a></li> <li><a class="current-page">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>