diff --git a/pom.xml b/pom.xml
index 5a043114d..f3dfef482 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,7 +67,7 @@
org.janelia.saalfeldlab.paintera.Paintera
Paintera
paintera
- 1.3.0
+ 1.3.4
javafx.base,javafx.controls,javafx.fxml,javafx.media,javafx.swing,javafx.web,javafx.graphics,java.naming,java.management,java.sql
UTF-8
f918b6f9-8685-4b50-9fbd-9be7a1209249
diff --git a/src/main/java/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDatasetHandler.java b/src/main/java/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDatasetHandler.java
index 1bb58cc56..f5287ef96 100644
--- a/src/main/java/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDatasetHandler.java
+++ b/src/main/java/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDatasetHandler.java
@@ -53,13 +53,13 @@ private static void createAndAddNewLabelDataset(
public static void createAndAddNewLabelDataset(
final PainteraBaseView pbv,
- final Supplier projecDirectory,
+ final Supplier projectDirectory,
final Consumer exceptionHandler,
final Source> currentSource,
final Source>... allSources) {
try {
- createAndAddNewLabelDataset(pbv, projecDirectory, currentSource, allSources);
+ createAndAddNewLabelDataset(pbv, projectDirectory, currentSource, allSources);
} catch (final Exception e) {
exceptionHandler.accept(e);
}
diff --git a/src/main/java/org/janelia/saalfeldlab/util/n5/N5Data.java b/src/main/java/org/janelia/saalfeldlab/util/n5/N5Data.java
index 5f106925f..52f5ebfca 100644
--- a/src/main/java/org/janelia/saalfeldlab/util/n5/N5Data.java
+++ b/src/main/java/org/janelia/saalfeldlab/util/n5/N5Data.java
@@ -35,7 +35,6 @@
import org.janelia.saalfeldlab.n5.imglib2.N5Utils;
import org.janelia.saalfeldlab.n5.universe.metadata.N5SpatialDatasetMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.SpatialMultiscaleMetadata;
-import org.janelia.saalfeldlab.paintera.Paintera;
import org.janelia.saalfeldlab.paintera.cache.WeakRefVolatileCache;
import org.janelia.saalfeldlab.paintera.data.DataSource;
import org.janelia.saalfeldlab.paintera.data.n5.N5DataSource;
@@ -69,7 +68,7 @@ public class N5Data {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param priority in fetching queue
* @param data type
@@ -95,7 +94,7 @@ ImagesWithTransform openRaw(
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param transform transforms voxel data into real world coordinates
* @param priority in fetching queue
@@ -131,7 +130,7 @@ DataSource openRawAsSource(
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param transform transforms voxel data into real world coordinates
* @param priority in fetching queue
@@ -163,7 +162,7 @@ DataSource openScalarAsSource(
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param transform transforms voxel data into real world coordinates
* @param priority in fetching queue
@@ -197,7 +196,7 @@ DataSource openScalarAsSource(
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param transform transforms voxel data into real world coordinates
* @param priority in fetching queue
@@ -256,7 +255,7 @@ ImagesWithTransform openRaw(
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param transform transforms voxel data into real world coordinates
* @param priority in fetching queue
@@ -287,7 +286,7 @@ ImagesWithTransform openRaw(
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param priority in fetching queue
* @param data type
@@ -314,7 +313,7 @@ ImagesWithTransform[] openRawMultiscale(
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param resolution voxel resolution
* @param offset offset in real world coordinates
@@ -419,7 +418,7 @@ ImagesWithTransform[] openRawMultiscale(
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param transform transforms voxel data into real world coordinates
* @param priority in fetching queue
@@ -481,7 +480,7 @@ public static ImagesWithTransform
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param priority in fetching queue
* @return image data with cache invalidation
@@ -504,7 +503,7 @@ public static ImagesWithTransform
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param resolution voxel size
* @param offset in world coordinates
@@ -560,7 +559,7 @@ public static ImagesWithTransform
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param priority in fetching queue
* @return multi-scale image data with cache invalidation
@@ -583,7 +582,7 @@ public static ImagesWithTransform[
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param resolution voxel size
* @param offset in world coordinates
@@ -652,7 +651,7 @@ public static ImagesWithTransform[
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param transform from voxel space to world coordinates
* @param priority in fetching queue
@@ -705,7 +704,7 @@ public static ImagesWithTransform[
}
/**
- * @param reader container
+ * @param reader N5Reader
* @param dataset dataset
* @param transform transforms voxel data into real world coordinates
* @param priority in fetching queue
@@ -716,8 +715,7 @@ public static ImagesWithTransform[
* @throws IOException if any N5 operation throws {@link IOException}
*/
@SuppressWarnings("unchecked")
- public static , T extends NativeType> DataSource
- openAsLabelSource(
+ public static , T extends NativeType> DataSource openAsLabelSource(
final N5Reader reader,
final String dataset,
final AffineTransform3D transform,
@@ -731,8 +729,8 @@ public static ImagesWithTransform[
}
/**
- * @param container container
- * @param group target group in {@code container}
+ * @param writer N5Writer
+ * @param group target group in {@code writer}
* @param dimensions size
* @param blockSize chunk size
* @param resolution voxel size
@@ -743,7 +741,7 @@ public static ImagesWithTransform[
* @throws IOException if any n5 operation throws {@link IOException}
*/
public static void createEmptyLabelDataset(
- final String container,
+ final N5Writer writer,
final String group,
final long[] dimensions,
final int[] blockSize,
@@ -753,12 +751,12 @@ public static void createEmptyLabelDataset(
@Nullable final int[] maxNumEntries,
final boolean labelMultiset) throws IOException {
- createEmptyLabelDataset(container, group, dimensions, blockSize, resolution, offset, relativeScaleFactors, maxNumEntries, labelMultiset, false);
+ createEmptyLabelDataset(writer, group, dimensions, blockSize, resolution, offset, relativeScaleFactors, maxNumEntries, labelMultiset, false);
}
/**
- * @param container container
- * @param group target group in {@code container}
+ * @param writer N5Writer
+ * @param group target group in {@code writer}
* @param dimensions size
* @param blockSize chunk size
* @param resolution voxel size
@@ -771,7 +769,7 @@ public static void createEmptyLabelDataset(
* already exists and {@code ignorExisting} is {@code false}
*/
public static void createEmptyLabelDataset(
- final String container,
+ final N5Writer writer,
final String group,
final long[] dimensions,
final int[] blockSize,
@@ -784,35 +782,35 @@ public static void createEmptyLabelDataset(
final Map pd = new HashMap<>();
pd.put("type", "label");
- final N5Writer n5 = Paintera.getN5Factory().newWriter(container);
final String uniqueLabelsGroup = String.format("%s/unique-labels", group);
- if (!ignoreExisiting && n5.datasetExists(group))
- throw new IOException(String.format("Dataset `%s' already exists in container `%s'", group, container));
+ var n5Uri = writer.getURI();
+ if (!ignoreExisiting && writer.datasetExists(group))
+ throw new IOException(String.format("Dataset `%s' already exists in container `%s'", group, n5Uri));
- if (!n5.exists(group))
- n5.createGroup(group);
+ if (!writer.exists(group))
+ writer.createGroup(group);
- if (!ignoreExisiting && n5.getAttribute(group, N5Helpers.PAINTERA_DATA_KEY, JsonObject.class) != null)
- throw new IOException(String.format("Group '%s' already exists in container '%s' and is a Paintera dataset", group, container));
+ if (!ignoreExisiting && writer.getAttribute(group, N5Helpers.PAINTERA_DATA_KEY, JsonObject.class) != null)
+ throw new IOException(String.format("Group '%s' already exists in container '%s' and is a Paintera dataset", group, n5Uri));
- if (!ignoreExisiting && n5.exists(uniqueLabelsGroup))
- throw new IOException(String.format("Unique labels group '%s' already exists in container '%s' -- conflict likely.", uniqueLabelsGroup, container));
+ if (!ignoreExisiting && writer.exists(uniqueLabelsGroup))
+ throw new IOException(String.format("Unique labels group '%s' already exists in container '%s' -- conflict likely.", uniqueLabelsGroup, n5Uri));
- n5.setAttribute(group, N5Helpers.PAINTERA_DATA_KEY, pd);
- n5.setAttribute(group, N5Helpers.MAX_ID_KEY, 0L);
+ writer.setAttribute(group, N5Helpers.PAINTERA_DATA_KEY, pd);
+ writer.setAttribute(group, N5Helpers.MAX_ID_KEY, 0L);
final String dataGroup = String.format("%s/data", group);
- n5.createGroup(dataGroup);
+ writer.createGroup(dataGroup);
- n5.setAttribute(dataGroup, N5Helpers.MULTI_SCALE_KEY, true);
- n5.setAttribute(dataGroup, N5Helpers.OFFSET_KEY, offset);
- n5.setAttribute(dataGroup, N5Helpers.RESOLUTION_KEY, resolution);
- n5.setAttribute(dataGroup, N5Helpers.IS_LABEL_MULTISET_KEY, labelMultisetType);
+ writer.setAttribute(dataGroup, N5Helpers.MULTI_SCALE_KEY, true);
+ writer.setAttribute(dataGroup, N5Helpers.OFFSET_KEY, offset);
+ writer.setAttribute(dataGroup, N5Helpers.RESOLUTION_KEY, resolution);
+ writer.setAttribute(dataGroup, N5Helpers.IS_LABEL_MULTISET_KEY, labelMultisetType);
- n5.createGroup(uniqueLabelsGroup);
- n5.setAttribute(uniqueLabelsGroup, N5Helpers.MULTI_SCALE_KEY, true);
+ writer.createGroup(uniqueLabelsGroup);
+ writer.setAttribute(uniqueLabelsGroup, N5Helpers.MULTI_SCALE_KEY, true);
final String scaleDatasetPattern = String.format("%s/s%%d", dataGroup);
final String scaleUniqueLabelsPattern = String.format("%s/s%%d", uniqueLabelsGroup);
@@ -830,17 +828,17 @@ public static void createEmptyLabelDataset(
final String uniqeLabelsDataset = String.format(scaleUniqueLabelsPattern, scaleLevel);
if (labelMultisetType) {
- n5.createDataset(dataset, scaledDimensions, blockSize, DataType.UINT8, new GzipCompression());
+ writer.createDataset(dataset, scaledDimensions, blockSize, DataType.UINT8, new GzipCompression());
final int maxNum = downscaledLevel < 0 ? -1 : maxNumEntries[downscaledLevel];
- n5.setAttribute(dataset, N5Helpers.MAX_NUM_ENTRIES_KEY, maxNum);
- n5.setAttribute(dataset, N5Helpers.IS_LABEL_MULTISET_KEY, true);
+ writer.setAttribute(dataset, N5Helpers.MAX_NUM_ENTRIES_KEY, maxNum);
+ writer.setAttribute(dataset, N5Helpers.IS_LABEL_MULTISET_KEY, true);
} else
- n5.createDataset(dataset, scaledDimensions, blockSize, DataType.UINT64, new GzipCompression());
+ writer.createDataset(dataset, scaledDimensions, blockSize, DataType.UINT64, new GzipCompression());
- n5.createDataset(uniqeLabelsDataset, scaledDimensions, blockSize, DataType.UINT64, new GzipCompression());
+ writer.createDataset(uniqeLabelsDataset, scaledDimensions, blockSize, DataType.UINT64, new GzipCompression());
if (scaleLevel != 0) {
- n5.setAttribute(dataset, N5Helpers.DOWNSAMPLING_FACTORS_KEY, accumulatedFactors);
- n5.setAttribute(uniqeLabelsDataset, N5Helpers.DOWNSAMPLING_FACTORS_KEY, accumulatedFactors);
+ writer.setAttribute(dataset, N5Helpers.DOWNSAMPLING_FACTORS_KEY, accumulatedFactors);
+ writer.setAttribute(uniqeLabelsDataset, N5Helpers.DOWNSAMPLING_FACTORS_KEY, accumulatedFactors);
}
}
}
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt
index 82596a661..2f0420c8d 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt
@@ -117,8 +117,8 @@ class PainteraMainWindow(val gateway: PainteraGateway = PainteraGateway()) {
{ projectDirectory.actualDirectory.absolutePath },
{ indexToState[it] })
val gson = builder.create()
- val json = projectDirectory.actualDirectory
- ?.let { Paintera.n5Factory.openReader(it.absolutePath).getAttribute("/", PAINTERA_KEY, JsonElement::class.java) }
+ val json = projectDirectory.actualDirectory.absolutePath
+ .let { Paintera.n5Factory.openReader(it).getAttribute("/", PAINTERA_KEY, JsonElement::class.java) }
?.takeIf { it.isJsonObject }
?.asJsonObject
Paintera.n5Factory.gsonBuilder(builder)
@@ -156,7 +156,7 @@ class PainteraMainWindow(val gateway: PainteraGateway = PainteraGateway()) {
fun save(notify: Boolean = true) {
- /* Not allowd to save if any source is RAI */
+ /* Not allowed to save if any source is RAI */
baseView.sourceInfo().canSourcesBeSerialized().nullable?.let { reasonSoureInfoCannotBeSerialized ->
val alert = PainteraAlerts.alert(Alert.AlertType.WARNING)
alert.title = "Cannot Serialize All Sources"
@@ -184,7 +184,7 @@ class PainteraMainWindow(val gateway: PainteraGateway = PainteraGateway()) {
}
}
- /* Change back to the currect mode. */
+ /* Change back to the correct mode. */
baseView.changeMode(curMode)
}
@@ -331,11 +331,9 @@ class PainteraMainWindow(val gateway: PainteraGateway = PainteraGateway()) {
private const val TILDE = "~"
- private fun replaceUserHomeWithTilde(path: String) = if (path.startsWith(USER_HOME)) path.replaceFirst(USER_HOME, TILDE) else path
+ internal fun String.homeToTilde() = if (startsWith(USER_HOME)) replaceFirst(USER_HOME, TILDE) else this
- internal fun String.homeToTilde() = replaceUserHomeWithTilde(this)
-
- internal fun String.tildeToHome() = if (this.startsWith(TILDE)) this.replaceFirst(TILDE, USER_HOME) else this
+ internal fun String.tildeToHome() = if (startsWith(TILDE)) replaceFirst(TILDE, USER_HOME) else this
}
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDataset.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDataset.kt
index 2e05a36f8..1de3afa03 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDataset.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDataset.kt
@@ -40,6 +40,7 @@ import org.janelia.saalfeldlab.fx.ui.ObjectField.Companion.stringField
import org.janelia.saalfeldlab.fx.ui.ObjectField.SubmitOn
import org.janelia.saalfeldlab.fx.ui.SpatialField
import org.janelia.saalfeldlab.fx.util.InvokeOnJavaFXApplicationThread
+import org.janelia.saalfeldlab.n5.N5KeyValueWriter
import org.janelia.saalfeldlab.paintera.Constants
import org.janelia.saalfeldlab.paintera.Paintera
import org.janelia.saalfeldlab.paintera.Paintera.Companion.n5Factory
@@ -47,6 +48,7 @@ import org.janelia.saalfeldlab.paintera.Style.ADD_GLYPH
import org.janelia.saalfeldlab.paintera.Style.REMOVE_GLYPH
import org.janelia.saalfeldlab.paintera.data.mask.MaskedSource
import org.janelia.saalfeldlab.paintera.data.n5.N5DataSource
+import org.janelia.saalfeldlab.paintera.paintera
import org.janelia.saalfeldlab.paintera.state.SourceState
import org.janelia.saalfeldlab.paintera.state.metadata.MetadataState
import org.janelia.saalfeldlab.paintera.state.metadata.MetadataUtils.Companion.createMetadataState
@@ -117,7 +119,7 @@ class CreateDataset(private val currentSource: Source<*>?, vararg allSources: So
}
}
- private val n5Container: DirectoryField = DirectoryField(System.getProperty("user.home"), FIELD_WIDTH)
+ private val n5Container: DirectoryField = DirectoryField(paintera.projectDirectory.actualDirectory, FIELD_WIDTH)
private val dataset = stringField("", *SubmitOn.entries.toTypedArray()).apply {
textField.textProperty().addListener { _, _, newv: String? ->
if (!nameField.manuallyNamed && newv != null) {
@@ -253,7 +255,7 @@ class CreateDataset(private val currentSource: Source<*>?, vararg allSources: So
headerText = "Create new Label dataset"
dialogPane.content = pane
dialogPane.lookupButton(ButtonType.OK).addEventFilter(ActionEvent.ACTION) { e: ActionEvent ->
- val container = n5Container.directoryProperty().value!!.absolutePath
+ val container = n5Container.directoryProperty().value!!
val dataset = dataset.value
val name = nameField.text
LOG.debug { "Trying to create empty label dataset `$dataset' in container `$container'"}
@@ -274,8 +276,13 @@ class CreateDataset(private val currentSource: Source<*>?, vararg allSources: So
}
try {
+ val writer = n5Factory.newWriter(container.absolutePath)
+
+ if (labelMultiset.isSelected && writer !is N5KeyValueWriter)
+ throw UnsupportedOperationException("LabelMultisetType Label dataset only supported for N5 datasets")
+
N5Data.createEmptyLabelDataset(
- container,
+ writer,
dataset,
dimensions.asLongArray(),
blockSize.asIntArray(),
@@ -286,7 +293,6 @@ class CreateDataset(private val currentSource: Source<*>?, vararg allSources: So
labelMultiset.isSelected
)
- val writer = n5Factory.openWriter(container)
N5Helpers.parseMetadata(writer, true).ifPresent { _ ->
val containerState = N5ContainerState(writer)
createMetadataState(containerState, dataset).ifPresent { metadataStateProp.set(it) }
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/util/n5/N5Helpers.kt b/src/main/kotlin/org/janelia/saalfeldlab/util/n5/N5Helpers.kt
index b52e27f91..5bed78804 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/util/n5/N5Helpers.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/util/n5/N5Helpers.kt
@@ -49,9 +49,7 @@ import org.janelia.saalfeldlab.util.n5.metadata.N5PainteraDataMultiScaleMetadata
import org.janelia.saalfeldlab.util.n5.metadata.N5PainteraLabelMultiScaleGroup.PainteraLabelMultiScaleParser
import org.janelia.saalfeldlab.util.n5.metadata.N5PainteraRawMultiScaleGroup.PainteraRawMultiScaleParser
import org.janelia.saalfeldlab.util.n5.universe.N5ContainerDoesntExist
-import org.slf4j.LoggerFactory
import java.io.IOException
-import java.lang.invoke.MethodHandles
import java.util.*
import java.util.List
import java.util.concurrent.ExecutorService
@@ -791,7 +789,9 @@ object N5Helpers {
?.asJsonObject?.get("data")
?.asJsonObject?.let { it.get("basePath") ?: it.get("file") }
?.asString
- val uri = fromClassInfo ?: json[URI]?.asString ?: paintera.projectDirectory.actualDirectory.toURI().toString()
+ val uri = fromClassInfo
+ ?: json[URI]?.asString
+ ?: paintera.projectDirectory.actualDirectory.absolutePath
return getN5ContainerWithRetryPrompt(uri)
}
diff --git a/src/main/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCache.kt b/src/main/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCache.kt
index 0f4b30447..586ebba92 100644
--- a/src/main/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCache.kt
+++ b/src/main/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCache.kt
@@ -7,18 +7,56 @@ import org.janelia.saalfeldlab.n5.N5Writer
import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader
import org.janelia.saalfeldlab.n5.universe.N5Factory
import org.slf4j.LoggerFactory
+import java.io.File
import java.lang.invoke.MethodHandles
+import java.net.URI
+import java.nio.file.Path
+import java.nio.file.Paths
+import kotlin.io.path.toPath
class N5FactoryWithCache : N5Factory() {
companion object {
private val LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())
+
+ private const val ZGROUP = ".zgroup"
+ private const val ZARRAY = ".zarray"
+ private const val ZATTRS = ".zattrs"
+ private const val N5_ATTRIBUTES = "attributes.json"
+
+ /** Check for existing of N5 and zarr specific files to indicate the format
+ **/
+ internal fun File.guessStorageFromFormatSpecificFiles() : StorageFormat? = when {
+ resolve(N5_ATTRIBUTES).exists() -> StorageFormat.N5
+ listOf(ZGROUP, ZARRAY, ZATTRS).any { resolve(it).exists() } -> StorageFormat.ZARR
+ else -> null
+ }
}
private val writerCache = HashMap()
private val readerCache = HashMap()
- override fun openReader(uri: String): N5Reader {
- return getFromReaderCache(uri) ?: getFromWriterCache(uri) ?: super.openReader(uri).let {
+
+ private fun parseUriWithN5Default(uri: String) : Pair {
+ return StorageFormat.parseUri(uri).run {
+ val fileBasedFormatCheck = if (a == null && (b.scheme == null || b.scheme == "file")) {
+ File(b.path).guessStorageFromFormatSpecificFiles()
+ } else null
+ (a ?: fileBasedFormatCheck ?: StorageFormat.N5) to b
+ }
+ }
+
+ private fun openWriterDefaultN5(uri: String) : N5Writer {
+ val (format, asUri) = parseUriWithN5Default(uri)
+ return super.openWriter(format, asUri)
+ }
+
+ private fun openReaderDefaultN5(uri: String) : N5Reader {
+ val (format, asUri) = parseUriWithN5Default(uri)
+ return super.openReader(format, asUri)
+ }
+
+ override fun openReader(uri: String): N5Reader {
+ return getFromReaderCache(uri) ?: getFromWriterCache(uri) ?: openReaderDefaultN5(uri).let {
if (containerIsReadable(it)) {
readerCache[uri] = it
it
@@ -130,7 +168,7 @@ class N5FactoryWithCache : N5Factory() {
}
private fun createAndCacheN5Writer(uri: String): N5Writer {
- val n5Writer = super.openWriter(uri)
+ val n5Writer = openWriterDefaultN5(uri)
/* See if we have write permissions before we declare success */
n5Writer.setAttribute("/", N5Reader.VERSION_KEY, n5Writer.version.toString())
if (readerCache[uri] == null) {
diff --git a/src/test/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCacheTest.kt b/src/test/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCacheTest.kt
new file mode 100644
index 000000000..f07b95e81
--- /dev/null
+++ b/src/test/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCacheTest.kt
@@ -0,0 +1,43 @@
+package org.janelia.saalfeldlab.util.n5.universe
+
+import org.assertj.core.util.Files
+import org.janelia.saalfeldlab.n5.N5KeyValueReader
+import org.janelia.saalfeldlab.n5.N5KeyValueWriter
+import org.janelia.saalfeldlab.n5.zarr.ZarrKeyValueReader
+import org.janelia.saalfeldlab.n5.zarr.ZarrKeyValueWriter
+import org.janelia.saalfeldlab.paintera.Paintera
+import kotlin.test.Test
+import kotlin.test.assertTrue
+
+class PainteraMainWindowTest {
+
+ @Test
+ fun `project directory as n5 or zarr`() {
+ val chars : List = ('a'..'z') + ('A'..'Z') + ('0'..'9')
+ val randString = { List(10) { chars.random() }.joinToString("") }
+
+ val noExtension = Files.temporaryFolder().resolve(randString()).absolutePath
+ assertTrue { Paintera.n5Factory.newWriter(noExtension) is N5KeyValueWriter }
+ assertTrue { Paintera.n5Factory.openReader(noExtension) is N5KeyValueReader }
+
+ val noExtension2 = Files.temporaryFolder().resolve(randString()).absolutePath
+ assertTrue("no extension with zarr: should be zarr") { Paintera.n5Factory.newWriter("zarr:${noExtension2}") is ZarrKeyValueWriter }
+ assertTrue("No extension with .zgroup and no scheme should be zarr") { Paintera.n5Factory.openReader(noExtension2) is ZarrKeyValueReader }
+
+ val nonsenseExtension = Files.temporaryFolder().resolve("${randString()}.asdf").absolutePath
+ assertTrue("random extension should be n5") { Paintera.n5Factory.newWriter(nonsenseExtension) is N5KeyValueWriter }
+ assertTrue("random extension should be n5") { Paintera.n5Factory.openReader(nonsenseExtension) is N5KeyValueReader }
+
+ val nonsenseExtension2 = Files.temporaryFolder().resolve("${randString()}.asdf").absolutePath
+ assertTrue("random extension with zarr: should be zarr") { Paintera.n5Factory.newWriter("zarr:$nonsenseExtension2") is ZarrKeyValueWriter }
+ assertTrue("random extension with zarr: should be zarr") { Paintera.n5Factory.openReader(nonsenseExtension2) is ZarrKeyValueReader }
+
+ val zarrFile = Files.temporaryFolder().resolve("${randString()}.zarr").absolutePath
+ assertTrue(".zarr should be zarr") { Paintera.n5Factory.newWriter(zarrFile) is ZarrKeyValueWriter }
+ assertTrue(".zarr should be zarr") { Paintera.n5Factory.openReader(zarrFile) is ZarrKeyValueReader }
+
+ val n5File = Files.temporaryFolder().resolve("${randString()}.n5").absolutePath
+ assertTrue(".n5 should be n5") { Paintera.n5Factory.newWriter(n5File) is N5KeyValueWriter }
+ assertTrue(".n5 should be n5 ") { Paintera.n5Factory.openReader(n5File) is N5KeyValueReader }
+ }
+}
\ No newline at end of file