Table of Contents
Coding in Scala
Environment
Though Scala could be a highly efficient tool for writing codes using ImageJ as library, there is no default setup in any of ImageJ distributions. One needs to setup the environment. Some IDEs seems to be usable for Scala coding:
To go simpler, I tried to setup environment with vim. One advantage of doing so is that it will enable streamed compiling (which will be more like runtime debugging) by combining vimshell(there are several different “vimshell”, but this one is the latest and most functional) and sbt. Here are more details on the setting.
Basics: Interactive Session (with ImageJ API)
scala
In your command line will startup the interactive session (read-evaluate-print looping, or REPL mode).
To use external classes, you could either
- copy corresponding jars to {SCALA_HOME}/lib/ directory
- in the scala prompt, do :cp={path to ij.jar}
- use SBT to include the classpath (details).
- in this case, start your scala session by a command screpl (a shell script that runs SBT in REPL mode) with dependency argument. The argument is similar to Maven: GroupId%Artifact%Version and if the dependency target is not locally saved, then URL is required.
screpl "imagej.releases at http://maven.imagej.net/content/repositories/releases" "net.imagej%ij%1.47e"
- Once ImageJ (ij.jar) is downloaded to your repository, of which the default location would be ~/.ivy2, you could use command without URL.
screpl "net.imagej%ij%1.47e"
Basics: Scripting (with ImageJ API)
The fastes way if you want test:
- Copy ij.jar under scala home directory
- If you installed scala in Windows using binary, lib/
- If you installed scala using homebrew, under /usr/local/Cellar/scala/{version.number}/libexec/lib/
- Run the code by
scala -howtorun:script testscript.scala
Basics: Compiling and Run
javac -cp {whatever path}/scala-library.jar:{imagej_home}/ij.jar my_plugin.scala java -cp {whatever path}/scala-library.jar:{imagej_home}/ij.jar my_plugin (you could prepare plugins.config) jar cvf my_plugin.jar * cp my_plugin.jar {imagej_home}/plugins/
Or If you have scala compiler (scalac) in your path, then
scalac -classpath {imagej_home}/ij.jar my_plugin.scala
SBT-Scala
SBT stands for Simple Build Tool, and is a build tool for Scala. It's function is similar to Make, Ant or Maven.
Scripting
SBT could be used in ScriptMode to load Scala scripts and execute (details). Merit of using SBT is that you could write the dependency directly in the scala file as a header. This header works like a pom.xml dependency nodes in Maven, searches for library in internet and downloads if necessary.
For this to work, a short shell script that runs java command “scalas” is used. How to prepare this script is written in the above “details” link.
example script
The code below, the file name is, say, testsc.scala. Then you could run the script by
scalas testsc.scala
If scalas is within $PATH then
./testsc.scala
Dont forget to chmod u+x the script file.
#!/usr/bin/env scalas !# /*** scalaVersion := "2.9.2" libraryDependencies ++= Seq( "net.imagej" % "ij" % "1.47e" ) */ import ij._ println("scala script running by SBT script mode") IJ.log("here is via IJ.log")
Compile
To compile scala code and generate .class files that could be then packaged as a jar file, you should prepare a build.sbt file (similar to pom.xml in Maven but much shorter).
To use ImageJ API, below is an example of build.sbt file to automatically fullfil the dependency for ij.jar. This build file should be placed in the root directory of the project.
name := "hello" version := "1.0" scalaVersion := "2.9.2" resolvers += "imagej.releases" at "http://maven.imagej.net/content/repositories/releases" libraryDependencies += "net.imagej" % "ij" % "latest.integration"
First three lines (note: there should always be a blank row between lines in build.sbt file) are standard declaration of project. 4th line defines extra Maven repository site (called "resolver") and 5th line for the library (automatic dependency management).
With this build setting, declared dependencies, which in the above case would be the latest ij.jar, will be downloaded under local repository in ~/.ivy2.
ImageJ related library's groupID, name of the artefact, versions could be searched in the following site:
The repository at the Maven Central offers ImageJ builds, but this is not the official release.
The builds on Maven Central with groupId gov.nih.imagej were done by a third party, but the official ImageJ builds are available from Maven—just not from Maven Central yet.
The official builds are currently deployed to maven.imagej.net, with groupId net.imagej. The ImageJ 1.x builds have artifactId of ij while the ImageJ2 builds consist of several artifacts all prefixed by ij-.
Are ImageJ Maven dependencies in maven central? StackOverFlow, 20110917 Link
Compile and run the code for the first time with the above build file will download ij.jar.
$ sbt run [info] Set current project to hello (in build file:/Users/miura/tmp/sbttest2/) [info] Updating {file:/Users/miura/tmp/sbttest2/}default-74f0ba... [info] Resolving com.github.scijava#pom-scijava;1.4 ... [info] downloading http://maven.imagej.net/content/repositories/releases/net/imagej/ij/1.47d/ij-1.47d.jar ... [info] [SUCCESSFUL ] net.imagej#ij;1.47d!ij.jar (2394ms) [info] Done updating. [info] Running Hi Hi! [success] Total time: 6 s, completed Nov 6, 2012 1:01:34 PM
If you want to compile only, then
$ sbt compile
If you want to let the compiler to automatically react when you change a source file (meaning when you save the file), keep it running by
$ sbt ~compile # in case of VimShell, you should escape tilda and do "sbt \~compile"
sbt build using pom.xml
Dependency could be set using Maven pom.xml. It might be better to do so, as many ImageJ developers are using Maven as build tool. I have not tested this Maven-Sbt method, but if this is possible then simply copy pom.xml example file like the one shown in here to the project root directory and write build.sbt file to refer to that pom.xml.
externalPom()
For ImageJ2, one could refer to the pom.xml example shown here.
Note: it might not be straightforward, as relative path in pom.xml could be problematic for sbt.
Example Code
Here is a very simple code, placed in the same directory as the build.sbt above.
import ij._ object Hi { def main(args: Array[String]) { println("Hi!") IJ.log("test ij") IJ.log(IJ.getVersion()) var imp = IJ.openImage("http://imagej.nih.gov/ij/images/blobs.gif") imp.show() } }
THe code could be compiled and executed by sbt run.
vimshell% sbt run [info] Set current project to hello (in build file:/Users/miura/tmp/sbttest2/) [info] Compiling 1 Scala source to /Users/miura/tmp/sbttest2/target/scala-2.9.2/classes... [info] Running Hi Hi! test ij 1.47d [success] Total time: 3 s, completed Nov 6, 2012 1:32:48 PM
Maven-Scala
A bit more traditional way that Scala people has been using for building is Maven (I rephrase traditional. As long I have observed, Scala people are moving towards sbt, simple-build tool). There is Maven-Scala plugin(some information in this site is outdated) that enables to build Scala code using Maven pom.xml.
Since Maven is consistently used in Fiji and ImageJ2 development, it might be better to keep the consistency and use Maven.
Running Scala Script using ImageJ as library
Scala has three modes of execution: compile, script and interactive. Here is an example of running script. Place a pom.xml as follows in a directory.
<?xml version="1.0" encoding="UTF-8"?> <!-- > This pom.xml is for running Scala Script with ImageJ. run the script with the following command. mvn scala:script <--> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.scijava</groupId> <artifactId>pom-scijava</artifactId> <version>1.19</version> </parent> <groupId>de.embl.cmci</groupId> <artifactId>testscript</artifactId> <name>test-scala-ij-script</name> <description></description> <!--> repos: ImageJ release + scala tools <--> <repositories> <repository> <id>imagej.releases</id> <url>http://maven.imagej.net/content/repositories/releases</url> </repository> <repository> <id>scala-tools.org</id> <name>Scala-tools Maven2 Repository</name> <!-- <url>http://scala-tools.org/repo-releases</url> --> <url>http://oss.sonatype.org/content/groups/scala-tools</url> </repository> </repositories> <!--> plugin repo: Maven - Scala <--> <pluginRepositories> <pluginRepository> <id>scala-tools.org</id> <name>Scala-tools Maven2 Repository</name> <!-- <url>http://scala-tools.org/repo-releases</url> --> <url>http://oss.sonatype.org/content/groups/scala-tools</url> </pluginRepository> </pluginRepositories> <dependencies> <dependency> <groupId>net.imagej</groupId> <artifactId>ij</artifactId> <version>${imagej1.version}</version> </dependency> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>2.9.2</version> </dependency> <!-- <dependency> <groupId>org.scala-tools</groupId> <artifactId>maven-scala-plugin</artifactId> <version>2.15.2</version> </dependency> --> </dependencies> <!--> build environment<--> <build> <sourceDirectory>src/main/scala</sourceDirectory> <testSourceDirectory>src/test/scala</testSourceDirectory> <plugins> <plugin> <groupId>org.scala-tools</groupId> <artifactId>maven-scala-plugin</artifactId> <version>2.15.2</version> <executions> <execution> <phase>package</phase> <goals> <goal>script</goal> </goals> </execution> </executions> <!-- to set the exact version <configuration> <scalaVersion>${scala.version}</scalaVersion> </configuration> --> <!-- if you want write script here <configuration> <script> println ("Hello from pom.xml") </script> </configuration> --> <!-- or set the script file name here <configuration> <scriptFile>helloscript.scala</scriptFile> </configuration> --> </plugin> </plugins> </build> </project>Gist
Then in the same directory, save the following script as “helloscript.scala”.
import ij._ println ("Hello from external script :-)") IJ.log("test ij") IJ.log(IJ.getVersion()) val imp = IJ.openImage("http://imagej.nih.gov/ij/images/blobs.gif") imp.show() IJ.wait(2000) imp.close()Gist
To run the script, use the following command:
mvn scala:script -DscriptFile=helloscript.scala
If this is the first time that you are using scala in this way, Maven downloads all the required libraries from oss.sonatype.org and maven.imagej.net. These files will be saved under ~/.m2 directory, and for executing the script. From the second time, Maven only checks the presence of the library under ./m2.
Instead of passing file name as command line argument, you could write the script directly in the file (see line 86 - 91) or set the script file path (see line 93-96). In this case, you could run the script by
mvn scala:script
In these cases, you could only have one of either <script> or <scriptFile> within <configure>.
Compiling Scala code
In compiler mode, source files should be placed under
src/main/scala src/test/scala
Maven could also startup a server that awaits changes in the source file and as soon there is change, then the source is compiled automatically. To use this feature (like “sbt ~compile”) use this command:
mvn scala:cc
And a pom.xml with scala dependency should be placed in the root (just like Maven with Java). Below is a sample pom.xml for this.
<?xml version="1.0" encoding="UTF-8"?> <!-- > This pom.xml is for building Scala code that uses ImageJ. <--> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.scijava</groupId> <artifactId>pom-scijava</artifactId> <version>1.19</version> </parent> <groupId>de.embl.cmci</groupId> <artifactId>testscalaCompile</artifactId> <name>test-scala-ij</name> <description></description> <!--> repos: ImageJ release + scala tools <--> <repositories> <repository> <id>imagej.releases</id> <url>http://maven.imagej.net/content/repositories/releases</url> </repository> <repository> <id>scala-tools.org</id> <name>Scala-tools Maven2 Repository</name> <!-- <url>http://scala-tools.org/repo-releases</url> --> <url>http://oss.sonatype.org/content/groups/scala-tools</url> </repository> </repositories> <!--> plugin repo: Maven - Scala <--> <pluginRepositories> <pluginRepository> <id>scala-tools.org</id> <name>Scala-tools Maven2 Repository</name> <!-- <url>http://scala-tools.org/repo-releases</url> --> <url>http://oss.sonatype.org/content/groups/scala-tools</url> </pluginRepository> </pluginRepositories> <dependencies> <dependency> <groupId>net.imagej</groupId> <artifactId>ij</artifactId> <version>${imagej1.version}</version> </dependency> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>2.9.2</version> </dependency> </dependencies> <!--> build environment<--> <build> <sourceDirectory>src/main/scala</sourceDirectory> <testSourceDirectory>src/test/scala</testSourceDirectory> <plugins> <plugin> <groupId>org.scala-tools</groupId> <artifactId>maven-scala-plugin</artifactId> <version>2.15.2</version> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> </execution> </executions> <!-- to set the exact version <configuration> <scalaVersion>${scala.version}</scalaVersion> </configuration> --> </plugin> </plugins> </build> </project>