diff --git a/.github/workflows/build_jar.yml b/.github/workflows/build_jar.yml index 4503d92..90d8985 100644 --- a/.github/workflows/build_jar.yml +++ b/.github/workflows/build_jar.yml @@ -10,15 +10,15 @@ runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: - java-version: '11' + java-version: '21' distribution: 'adopt-hotspot' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle - run: ./gradlew build -P toolchain=11 + run: ./gradlew build -P toolchain=21 - uses: actions/upload-artifact@v2 with: name: jar diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 0566ee6..3795720 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -10,12 +10,12 @@ runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: - java-version: '11' + java-version: '21' distribution: 'adopt-hotspot' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle - run: ./gradlew build -P toolchain=11 + run: ./gradlew build -P toolchain=21 diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 621bbf1..91c96d8 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -14,12 +14,12 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2 with: - java-version: '11' + java-version: '21' distribution: 'adopt-hotspot' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Publish package - run: ./gradlew publish -P toolchain=11 -P release=true + run: ./gradlew publish -P toolchain=21 -P release=true env: MAVEN_USER: ${{ secrets.MAVEN_USER }} MAVEN_PASS: ${{ secrets.MAVEN_PASS }} diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index be94330..292b593 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -14,12 +14,12 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2 with: - java-version: '11' + java-version: '21' distribution: 'adopt-hotspot' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Publish package - run: ./gradlew publish -P toolchain=11 + run: ./gradlew publish -P toolchain=21 env: MAVEN_USER: ${{ secrets.MAVEN_USER }} MAVEN_PASS: ${{ secrets.MAVEN_PASS }} diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 60fd4af..0000000 --- a/build.gradle +++ /dev/null @@ -1,107 +0,0 @@ -plugins { - id 'java-library' - id 'maven-publish' - alias(libs.plugins.javafx) - -} - -repositories { - // Use this only for local development! - mavenLocal() - - maven{ - url "https://maven.scijava.org/content/repositories/releases" - } - - mavenCentral() - - maven { - url "https://maven.scijava.org/content/repositories/snapshots" - } -} - -ext.qupathVersion = gradle.ext.qupathVersion - -ext.moduleName = "qupath.extension.abba" - -description = "QuPath extension to use Aligning Big Brain and Atlases" - -group = "ch.epfl.biop" -version = "0.3.2" - -dependencies { - implementation("io.github.qupath:qupath-gui-fx:$qupathVersion") - implementation libs.bundles.logging - implementation("commons-io:commons-io:2.11.0") - implementation("net.imglib2:imglib2-realtransform:3.1.2") - implementation("qupath.ext.warpy:qupath-extension-warpy:0.3.0") - implementation libs.qupath.fxtras -} -tasks.register("copyDependencies", Copy) { - description "Copy dependencies into the output libs directory" - group "QuPath" - - from configurations.default - into 'build/libs' -} - -/* - * Ensure Java 11 compatibility - */ -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) - } - if ("sources" in project.properties) - withSourcesJar() - if ("javadocs" in project.properties) - withJavadocJar() -} - -jar { - // Important to set version so this can be queried within QuPath - manifest { - def manifestAttributes = [ - "Implementation-Vendor": "QuPath developers", - "Implementation-Version": project.version, - //'Automatic-Module-Name': group+ "." + moduleName, - "QuPath-build-time": new Date().format("yyyy-MM-dd, HH:mm") - ] - attributes(manifestAttributes) - } -} - -tasks.test { useJUnitPlatform() } - -publishing { - - repositories { - maven { - name = "scijava" - //credentials(PasswordCredentials::class) - if (version.toString().endsWith("SNAPSHOT")) { - url = uri("https://maven.scijava.org/content/repositories/snapshots") - } else { - url = uri("https://maven.scijava.org/content/repositories/releases") - } - credentials { - username = System.getenv("MAVEN_USER") - password = System.getenv("MAVEN_PASS") - } - } - } - - publications { - mavenJava(MavenPublication) { - from components.java - pom { - licenses { - license { - name = 'GNU General Public License, Version 3' - url = 'https://www.gnu.org/licenses/gpl-3.0.txt' - } - } - } - } - } -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..0e7f2e3 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,60 @@ +plugins { + // To optionally create a shadow/fat jar that bundle up any non-core dependencies + id("com.gradleup.shadow") version "8.3.5" + // QuPath Gradle extension convention plugin + id("qupath-conventions") + `maven-publish` +} + +qupathExtension { + name = "qupath-extension-abba" + group = "ch.epfl.biop" + version = "0.4.0-SNAPSHOT" + description = "QuPath extension to use Aligning Big Brain and Atlases" + automaticModule = "qupath.ext.biop.abba" +} + +dependencies { + // Main dependencies for most QuPath extensions + shadow(libs.bundles.qupath) + shadow(libs.bundles.logging) + shadow(libs.qupath.fxtras) + + implementation("commons-io:commons-io:2.11.0") + implementation("net.imglib2:imglib2-realtransform:4.0.3") + implementation("qupath.ext.warpy:qupath-extension-warpy:0.3.1") + // implementation("qupath.ext.warpy:qupath-extension-warpy:0.4.0") // supports QP 0.6.* +} + + + +publishing { + repositories { + maven { + name = "scijava" + //credentials(PasswordCredentials::class) + url = if (version.toString().endsWith("SNAPSHOT")) { + uri("https://maven.scijava.org/content/repositories/snapshots") + } else { + uri("https://maven.scijava.org/content/repositories/releases") + } + credentials { + username = System.getenv("MAVEN_USER") + password = System.getenv("MAVEN_PASS") + } + } + } + + publications { + create("mavenJava") { + pom { + licenses { + license { + name = "GNU General Public License, Version 3" + url = "https://www.gnu.org/licenses/gpl-3.0.txt" + } + } + } + } + } +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c..a4b76b9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1af9e09..cea7a79 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 index 0adc8e1..f5feea6 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -145,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +205,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 2578005..9b42019 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,92 +1,94 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega \ No newline at end of file +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 154ff52..0000000 --- a/settings.gradle +++ /dev/null @@ -1,26 +0,0 @@ -rootProject.name = "qupath-extension-abba" - -gradle.ext.qupathVersion = "0.5.0" - -dependencyResolutionManagement { - - repositories { - - mavenLocal() - - mavenCentral() - - maven { - url "https://maven.scijava.org/content/repositories/releases" - } - - maven { - url "https://maven.scijava.org/content/repositories/snapshots" - } - } - versionCatalogs { - libs { - from("io.github.qupath:qupath-catalog:${gradle.ext.qupathVersion}") - } - } -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..2299e46 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,18 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { + url = uri("https://maven.scijava.org/content/repositories/releases") + } + } +} + +// TODO: Specify which version of QuPath the extension is targeting here +qupath { + version = "0.6.0-SNAPSHOT" +} + +// Apply QuPath Gradle settings plugin to handle configuration +plugins { + id("io.github.qupath.qupath-extension-settings") version "0.2.1" +} diff --git a/src/main/java/qupath/ext/biop/abba/AtlasImporter.java b/src/main/java/qupath/ext/biop/abba/AtlasImporter.java index b00aac6..bb52f33 100644 --- a/src/main/java/qupath/ext/biop/abba/AtlasImporter.java +++ b/src/main/java/qupath/ext/biop/abba/AtlasImporter.java @@ -13,9 +13,9 @@ import qupath.ext.warpy.Warpy; import qupath.imagej.tools.IJTools; import qupath.lib.common.ColorTools; -import qupath.lib.gui.QuPathGUI; import qupath.lib.images.ImageData; -import qupath.lib.images.servers.ImageServer; +import qupath.lib.images.servers.ImageServerBuilder; +import qupath.lib.images.servers.ImageServerMetadata; import qupath.lib.images.servers.RotatedImageServer; import qupath.lib.measurements.MeasurementList; import qupath.lib.measurements.MeasurementListFactory; @@ -39,12 +39,16 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static qupath.ext.biop.abba.AtlasTools.getLazyNestedBuilders; +import static qupath.ext.biop.abba.AtlasTools.getLazyRotation; + public class AtlasImporter { private ImageData imageData; private String atlasName; @@ -107,7 +111,7 @@ AtlasImporter build() { loader.roiFile = loader.getAtlasRoiFile(); if( !loader.roiFile.exists()) { - logger.warn("No RoiSet file associated to image {} and Atlas {} found", imageData.getServer().getMetadata().getName(), loader.atlasName); + logger.warn("No RoiSet file associated to image {} and Atlas {} found", imageData.getServerMetadata().getName(), loader.atlasName); } // Load Ontology @@ -224,32 +228,31 @@ public List getFlattenedWarpedAtlasRegions() { rois.remove(left); rois.remove(right); - // Rotation for rotated servers - ImageServer server = imageData.getServer(); - AffineTransform transform = null; - - if (server instanceof RotatedImageServer) { + for (ImageServerBuilder.ServerBuilder serverBuilder: getLazyNestedBuilders(imageData)) { // The roi will need to be transformed before being imported - // First : get the rotation - RotatedImageServer ris = (RotatedImageServer) server; - switch (ris.getRotation()) { + Optional rotation; + if ((rotation = getLazyRotation(serverBuilder)).isEmpty()) + // the server is not rotated + continue; + ImageServerMetadata metadata = imageData.getServerMetadata(); + switch (rotation.get()) { case ROTATE_NONE: // No rotation. break; case ROTATE_90: // Rotate 90 degrees clockwise. transform = AffineTransform.getRotateInstance(Math.PI / 2.0); - transform.translate(0, -server.getWidth()); + transform.translate(0, -metadata.getWidth()); break; case ROTATE_180: // Rotate 180 degrees. transform = AffineTransform.getRotateInstance(Math.PI); - transform.translate(-server.getWidth(), -server.getHeight()); + transform.translate(-metadata.getWidth(), -metadata.getHeight()); break; case ROTATE_270: // Rotate 270 degrees transform = AffineTransform.getRotateInstance(Math.PI * 3.0 / 2.0); - transform.translate(-server.getHeight(), 0); + transform.translate(-metadata.getHeight(), 0); break; default: - System.err.println("Unknown rotation for rotated image server: " + ris.getRotation()); + System.err.println("Unknown rotation for rotated image server: " + rotation.get()); } } diff --git a/src/main/java/qupath/ext/biop/abba/AtlasTools.java b/src/main/java/qupath/ext/biop/abba/AtlasTools.java index e8fa0ec..f1fe073 100644 --- a/src/main/java/qupath/ext/biop/abba/AtlasTools.java +++ b/src/main/java/qupath/ext/biop/abba/AtlasTools.java @@ -13,9 +13,9 @@ import qupath.ext.warpy.Warpy; import qupath.imagej.tools.IJTools; import qupath.lib.common.ColorTools; -import qupath.lib.gui.QuPathGUI; import qupath.lib.images.ImageData; -import qupath.lib.images.servers.ImageServer; +import qupath.lib.images.servers.ImageServerBuilder; +import qupath.lib.images.servers.ImageServerMetadata; import qupath.lib.images.servers.RotatedImageServer; import qupath.lib.measurements.MeasurementList; import qupath.lib.measurements.MeasurementListFactory; @@ -36,12 +36,14 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; @@ -126,6 +128,35 @@ static PathObject getWarpedAtlasRegions(AtlasOntology ontology, ImageData getLazyRotation(ImageServerBuilder.ServerBuilder serverBuilder) { + try { + Field rotationField = serverBuilder.getClass().getDeclaredField("rotation"); + rotationField.setAccessible(true); + return Optional.of((RotatedImageServer.Rotation) rotationField.get(serverBuilder)); + } catch (NoSuchFieldException | IllegalAccessException e) { + return Optional.empty(); + } + } + + static Optional> getLazyWrappedBuilder(ImageServerBuilder.ServerBuilder serverBuilder) { + try { + Field builderField = serverBuilder.getClass().getDeclaredField("builder"); + builderField.setAccessible(true); + return Optional.of((ImageServerBuilder.ServerBuilder) builderField.get(serverBuilder)); + } catch (NoSuchFieldException | IllegalAccessException e) { + return Optional.empty(); + } + } + + static List> getLazyNestedBuilders(ImageData imageData) { + Optional> serverBuilder = Optional.of(imageData.getServerBuilder()); + List> builders = new ArrayList<>(); + do { + serverBuilder.ifPresent(builders::add); + } while ((serverBuilder = getLazyWrappedBuilder(serverBuilder.get())).isPresent()); + return builders.reversed(); // the order is from the innermost server to the outermost + } + public static List getFlattenedWarpedAtlasRegions(AtlasOntology ontology, ImageData imageData, boolean splitLeftRight) { Project project = QP.getProject(); @@ -158,32 +189,32 @@ public static List getFlattenedWarpedAtlasRegions(AtlasOntology onto rois.remove(left); rois.remove(right); - // Rotation for rotated servers - ImageServer server = imageData.getServer(); AffineTransform transform = null; - - if (server instanceof RotatedImageServer) { + for (ImageServerBuilder.ServerBuilder serverBuilder: getLazyNestedBuilders(imageData)) { // The roi will need to be transformed before being imported - // First : get the rotation - RotatedImageServer ris = (RotatedImageServer) server; - switch (ris.getRotation()) { + Optional rotation; + if ((rotation = getLazyRotation(serverBuilder)).isEmpty()) + // the server is not rotated + continue; + ImageServerMetadata metadata = imageData.getServerMetadata(); + switch (rotation.get()) { case ROTATE_NONE: // No rotation. break; case ROTATE_90: // Rotate 90 degrees clockwise. transform = AffineTransform.getRotateInstance(Math.PI/2.0); - transform.translate(0, -server.getWidth()); + transform.translate(0, -metadata.getWidth()); break; case ROTATE_180: // Rotate 180 degrees. transform = AffineTransform.getRotateInstance(Math.PI); - transform.translate(-server.getWidth(), -server.getHeight()); + transform.translate(-metadata.getWidth(), -metadata.getHeight()); break; case ROTATE_270: // Rotate 270 degrees transform = AffineTransform.getRotateInstance(Math.PI*3.0/2.0); - transform.translate(-server.getHeight(), 0); + transform.translate(-metadata.getHeight(), 0); break; default: - System.err.println("Unknown rotation for rotated image server: "+ris.getRotation()); + System.err.println("Unknown rotation for rotated image server: " + rotation.get()); } } @@ -355,30 +386,29 @@ public static RealTransform getAtlasToPixelTransform(ImageData im } RealTransform transformWithoutServerTransform = Warpy.getRealTransform(fTransform); - // Rotation for rotated servers - ImageServer server = imageData.getServer(); - AffineTransform3D transform = new AffineTransform3D(); - - if (server instanceof RotatedImageServer) { + for (ImageServerBuilder.ServerBuilder serverBuilder: getLazyNestedBuilders(imageData)) { // The roi will need to be transformed before being imported - // First : get the rotation - RotatedImageServer ris = (RotatedImageServer) server; - switch (ris.getRotation()) { + Optional rotation; + if ((rotation = getLazyRotation(serverBuilder)).isEmpty()) + // the server is not rotated + continue; + ImageServerMetadata metadata = imageData.getServerMetadata(); + switch (rotation.get()) { case ROTATE_NONE: // No rotation. break; case ROTATE_90: // Rotate 90 degrees clockwise. transform.set(new double[]{ - 0.0,-1.0, 0.0, server.getWidth(), + 0.0,-1.0, 0.0, metadata.getWidth(), 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 }); break; case ROTATE_180: // Rotate 180 degrees. transform.set(new double[]{ - -1.0, 0.0, 0.0, server.getWidth(), - 0.0,-1.0, 0.0, server.getHeight(), + -1.0, 0.0, 0.0, metadata.getWidth(), + 0.0,-1.0, 0.0, metadata.getHeight(), 0.0, 0.0, 1.0, 0.0 }); break; @@ -386,12 +416,12 @@ public static RealTransform getAtlasToPixelTransform(ImageData im // Rotate 90 degrees clockwise. transform.set(new double[]{ 0.0, 1.0, 0.0, 0.0, - -1.0, 0.0, 0.0, server.getHeight(), + -1.0, 0.0, 0.0, metadata.getHeight(), 0.0, 0.0, 1.0, 0.0 }); break; default: - System.err.println("Unknown rotation for rotated image server: "+ris.getRotation()); + System.err.println("Unknown rotation for rotated image server: " + rotation.get()); } } diff --git a/src/test/java/LaunchQuPath.java b/src/test/java/LaunchQuPath.java deleted file mode 100644 index dd4ae72..0000000 --- a/src/test/java/LaunchQuPath.java +++ /dev/null @@ -1,14 +0,0 @@ -import qupath.lib.gui.QuPathApp; - -public class LaunchQuPath { - - /** - * Main class for debugging - * - * @param args - */ - public static void main(String... args) { - //String projectPath = "\\\\svfas6.epfl.ch\\biop\\etx"; - QuPathApp.launch(QuPathApp.class);//, projectPath); - } -}