diff --git a/pom.xml b/pom.xml
index 5090caa..f6cec41 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,90 +50,52 @@
+
+ ${basedir}/../..
+ 1.8
+ 1.8
+ UTF-8
+
+ 0.0.5-SNAPSHOT
+ 2.20.0
+ 2.34.6
+
+
omeformats-api
- 7.3.1
-
-
- dev.zarr
- jzarr
- 0.4.2
-
-
- com.fasterxml.jackson.core
- jackson-databind
-
-
- com.fasterxml.jackson.core
- jackson-core
-
-
- com.fasterxml.jackson.core
- jackson-annotations
-
-
- org.apache.httpcomponents
- httpcore
-
-
+ 8.3.0
- org.mockito
- mockito-inline
- 3.7.7
- test
-
-
-
- org.testng
- testng
- 6.10
- test
+ dev.zarr
+ zarr-java
+ ${zarr-java.version}
-
-
-
- xalan
- serializer
- 2.7.3
- runtime
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
-
- xalan
- xalan
- 2.7.3
- runtime
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jdk8
+ ${jackson.version}
- com.amazonaws
- aws-java-sdk-s3
- 1.12.659
-
-
- commons-logging
- commons-logging
-
-
+ software.amazon.awssdk
+ s3
+ ${aws.version}
+
commons-loggingcommons-logging
- 1.2
+ 1.3.5
-
- ${basedir}/../..
- 1.8
- 1.8
- UTF-8
-
-
${project.basedir}/src${project.basedir}/test
diff --git a/src/loci/formats/S3FileSystemStore.java b/src/loci/formats/S3FileSystemStore.java
deleted file mode 100644
index 2d5a40f..0000000
--- a/src/loci/formats/S3FileSystemStore.java
+++ /dev/null
@@ -1,245 +0,0 @@
-package loci.formats;
-
-/*-
- * #%L
- * Implementation of Bio-Formats readers for the next-generation file formats
- * %%
- * Copyright (C) 2020 - 2022 Open Microscopy Environment
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-
-import com.bc.zarr.ZarrConstants;
-import com.bc.zarr.ZarrUtils;
-import com.bc.zarr.storage.Store;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.FileSystem;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.TreeSet;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.amazonaws.services.s3.AmazonS3;
-import com.amazonaws.services.s3.AmazonS3ClientBuilder;
-import com.amazonaws.services.s3.model.ListObjectsRequest;
-import com.amazonaws.services.s3.model.ObjectListing;
-import com.amazonaws.services.s3.model.S3Object;
-import com.amazonaws.services.s3.model.S3ObjectInputStream;
-import com.amazonaws.services.s3.model.S3ObjectSummary;
-import com.amazonaws.auth.AWSStaticCredentialsProvider;
-import com.amazonaws.auth.AnonymousAWSCredentials;
-import com.amazonaws.client.builder.AwsClientBuilder;
-
-public class S3FileSystemStore implements Store {
-
- private Path root;
- AmazonS3 client;
- public static final String ENDPOINT_PROTOCOL= "https://";
- protected static final Logger LOGGER =
- LoggerFactory.getLogger(S3FileSystemStore.class);
-
- public S3FileSystemStore(String path, FileSystem fileSystem) {
- if (fileSystem == null) {
- root = Paths.get(path);
- } else {
- root = fileSystem.getPath(path);
- }
- setupClient();
- }
-
- public void updateRoot(String path) {
- root = Paths.get(path);
- }
-
- public String getRoot() {
- return root.toString();
- }
-
- private void setupClient() {
- String[] pathSplit = root.toString().split(File.separator);
- String endpoint = ENDPOINT_PROTOCOL + pathSplit[1] + File.separator;
- try {
- client = AmazonS3ClientBuilder.standard()
- .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, "auto"))
- .withPathStyleAccessEnabled(true)
- .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())).build();
- } catch (Exception e) {
- LOGGER.info("Exception caught while constructing S3 client", e);
- }
-
- }
-
- public void close() {
- if (client != null) {
- client.shutdown();
- }
- }
-
- public S3FileSystemStore(Path rootPath) {
- root = rootPath;
- setupClient();
- }
-
- @Override
- public InputStream getInputStream(String key) throws IOException {
- // Get the base bucket name from splitting the root path and removing the prefixed protocol and end-point
- String[] pathSplit = root.toString().split(File.separator);
- String bucketName = pathSplit[2];
-
- // Append the desired key onto the remaining prefix
- String key2 = root.toString().substring(root.toString().indexOf(pathSplit[3]), root.toString().length()) + File.separator + key;
-
- try {
- S3Object o = client.getObject(bucketName, key2);
- S3ObjectInputStream responseStream = o.getObjectContent();
- return responseStream;
- } catch (Exception e) {
- LOGGER.info( "Unable to locate or access key: " + key2, e);
- }
-
- return null;
- }
-
- @Override
- public OutputStream getOutputStream(String key) throws IOException {
- final Path filePath = root.resolve(key);
- final Path dir = filePath.getParent();
- Files.createDirectories(dir);
- return Files.newOutputStream(filePath);
- }
-
- @Override
- public void delete(String key) throws IOException {
- final Path toBeDeleted = root.resolve(key);
- if (Files.isDirectory(toBeDeleted)) {
- ZarrUtils.deleteDirectoryTreeRecursively(toBeDeleted);
- }
- if (Files.exists(toBeDeleted)){
- Files.delete(toBeDeleted);
- }
- if (Files.exists(toBeDeleted)|| Files.isDirectory(toBeDeleted)) {
- throw new IOException("Unable to initialize " + toBeDeleted.toAbsolutePath().toString());
- }
- }
-
- @Override
- public TreeSet getArrayKeys() throws IOException {
- return getKeysFor(ZarrConstants.FILENAME_DOT_ZARRAY);
- }
-
- @Override
- public TreeSet getGroupKeys() throws IOException {
- return getKeysFor(ZarrConstants.FILENAME_DOT_ZGROUP);
- }
-
- /**
- * Copied from {@com.bc.zarr.storage.FileSystemStorage#getKeysEndingWith(String).
- *
- * @param suffix
- * @return
- * @throws IOException
- */
- public TreeSet getKeysEndingWith(String suffix) throws IOException {
- return (TreeSet)Files.walk(this.root).filter((path) -> {
- return path.toString().endsWith(suffix);
- }).map((path) -> {
- return this.root.relativize(path).toString();
- }).collect(Collectors.toCollection(TreeSet::new));
- }
-
- /**
- * Copied from {@com.bc.zarr.storage.FileSystemStorage#getRelativeLeafKeys(String).
- *
- * @param key
- * @return
- * @throws IOException
- */
- public Stream getRelativeLeafKeys(String key) throws IOException {
- Path walkingRoot = this.root.resolve(key);
- return Files.walk(walkingRoot).filter((path) -> {
- return !Files.isDirectory(path, new LinkOption[0]);
- }).map((path) -> {
- return walkingRoot.relativize(path).toString();
- }).map(ZarrUtils::normalizeStoragePath).filter((s) -> {
- return s.trim().length() > 0;
- });
- }
-
- private TreeSet getKeysFor(String suffix) throws IOException {
- TreeSet keys = new TreeSet();
-
- // Get the base bucket name from splitting the root path and removing the prefixed protocol and end-point
- String[] pathSplit = root.toString().split(File.separator);
- String bucketName = pathSplit[2];
-
- // Append the desired key onto the remaining prefix
- String key2 = root.toString().substring(root.toString().indexOf(pathSplit[3]), root.toString().length());
-
- ListObjectsRequest listObjectsRequest = new ListObjectsRequest()
- .withBucketName(bucketName)
- .withPrefix(key2)
- ;
-
- ObjectListing listObjectsResponse = null;
- String lastKey = null;
-
- do {
- if ( listObjectsResponse != null ) {
- listObjectsRequest = listObjectsRequest
- .withMarker(lastKey)
- ;
- }
-
- listObjectsResponse = client.listObjects(listObjectsRequest);
- List objects = listObjectsResponse.getObjectSummaries();
-
- // Iterate over results
- ListIterator iterVals = objects.listIterator();
- while (iterVals.hasNext()) {
- S3ObjectSummary object = (S3ObjectSummary) iterVals.next();
- String k = object.getKey();
- if (k.contains(suffix)) {
- String key = k.substring(k.indexOf(key2) + key2.length() + 1, k.indexOf(suffix));
- if (!key.isEmpty()) {
- keys.add(key.substring(0, key.length()-1));
- }
- }
- lastKey = k;
- }
- } while ( listObjectsResponse.isTruncated() );
-
- return keys;
- }
-}
\ No newline at end of file
diff --git a/src/loci/formats/in/ZarrReader.java b/src/loci/formats/in/ZarrReader.java
index bf8822f..b48ac75 100644
--- a/src/loci/formats/in/ZarrReader.java
+++ b/src/loci/formats/in/ZarrReader.java
@@ -31,9 +31,11 @@
import java.io.File;
import java.io.IOException;
+import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.ByteBuffer;
import java.nio.file.FileVisitOption;
import java.util.ArrayList;
import java.util.Collections;
@@ -51,9 +53,7 @@
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
-import com.bc.zarr.JZarrException;
-import com.bc.zarr.ZarrUtils;
-
+import dev.zarr.zarrjava.store.StoreHandle;
import loci.common.DataTools;
import loci.common.Location;
import loci.common.RandomAccessInputStream;
@@ -78,6 +78,7 @@
import ome.xml.model.primitives.PositiveInteger;
import ome.xml.model.primitives.Timestamp;
import loci.formats.services.OMEXMLService;
+import loci.formats.services.ZarrLocation;
import loci.formats.services.ZarrService;
@@ -112,6 +113,8 @@ public class ZarrReader extends FormatReader {
private boolean hasSPW = false;
private transient int currentOpenZarr = -1;
+ private ZarrLocation zarr;
+
public ZarrReader() {
super("Zarr", "zarr");
suffixSufficient = false;
@@ -129,11 +132,12 @@ public int getRequiredDirectories(String[] files)
/* @see loci.formats.IFormatReader#isThisType(String, boolean) */
@Override
public boolean isThisType(String name, boolean open) {
- Location zarrFolder = new Location(name);
- if (zarrFolder != null && zarrFolder.getAbsolutePath().toLowerCase().indexOf(".zarr") > 0) {
+ try {
+ new ZarrLocation(name);
return true;
+ } catch (URISyntaxException e) {
+ return false;
}
- return super.isThisType(name, open);
}
/* @see loci.formats.IFormatReader#close() */
@@ -179,96 +183,62 @@ protected void initFile(String id) throws FormatException, IOException {
super.initFile(id);
LOGGER.debug("ZarrReader attempting to initialize file: {}", id);
final MetadataStore store = makeFilterMetadata();
- Location zarrFolder = new Location(id);
- String zarrPath = zarrFolder.getAbsolutePath();
- String zarrRootPath = zarrPath.substring(0, zarrPath.indexOf(".zarr") + 5);
- String name = zarrRootPath.substring(zarrRootPath.lastIndexOf(File.separator)+1, zarrRootPath.length() - 5);
- Location omeMetaFile = new Location( zarrRootPath + File.separator + "OME", "METADATA.ome.xml" );
- String canonicalPath = new Location(zarrRootPath).getCanonicalPath();
-
- initializeZarrService();
- reloadOptionsFile(zarrRootPath);
+
+ try {
+ this.zarr = new ZarrLocation(id);
+ } catch (IllegalArgumentException | URISyntaxException e) {
+ throw new FormatException("Failed to initialize ZarrLocation", e);
+ }
+
+ StoreHandle omeMetaFile = zarr.getStoreHandle().resolve("OME", "METADATA.ome.xml" );
+
+ initializeZarrService(zarr);
+ reloadOptionsFile(zarr.getPath());
ArrayList omeSeriesOrder = new ArrayList();
if(omeMetaFile.exists()) {
LOGGER.debug("ZarrReader parsing existing OME-XML");
parseOMEXML(omeMetaFile, store, omeSeriesOrder);
}
+
// Parse base level attributes
- Map attr = zarrService.getGroupAttr(canonicalPath);
+ Map attr = zarr.metadataFromGroup("0");
+ if (attr.containsKey("ome")) {
+ attr = (Map) attr.get("ome");
+ }
int attrIndex = 0;
if (attr != null && !attr.isEmpty()) {
- parseResolutionCount(zarrRootPath, "", attr);
+ parseResolutionCount("0", attr);
parseOmeroMetadata(attr);
- if (saveAnnotations()) {
- String jsonAttr;
- try {
- jsonAttr = ZarrUtils.toJson(attr, true);
- store.setXMLAnnotationValue(jsonAttr, attrIndex);
- String xml_id = MetadataTools.createLSID("Annotation", attrIndex);
- store.setXMLAnnotationID(xml_id, attrIndex);
- } catch (JZarrException e) {
- LOGGER.warn("Failed to convert attributes to JSON");
- e.printStackTrace();
- }
- }
}
- generateGroupKeys(attr, canonicalPath);
- // Parse group attributes
- if (groupKeys.isEmpty()) {
- LOGGER.debug("ZarrReader adding group keys from ZarrService");
- groupKeys.addAll(zarrService.getGroupKeys(canonicalPath));
- }
+ if (attr.containsKey("plate")) {
+ generateGroupKeys(attr);
- List orderedGroupKeys = reorderGroupKeys(groupKeys, omeSeriesOrder);
- for (String key: orderedGroupKeys) {
- Map attributes = zarrService.getGroupAttr(canonicalPath+File.separator+key);
- if (attributes != null && !attributes.isEmpty()) {
- parseResolutionCount(zarrRootPath, key, attributes);
- parseLabels(zarrRootPath, attributes);
- parseImageLabels(zarrRootPath, attributes);
- attrIndex++;
- if (saveAnnotations()) {
- String jsonAttr;
- try {
- jsonAttr = ZarrUtils.toJson(attributes, true);
- store.setXMLAnnotationValue(jsonAttr, attrIndex);
- String xml_id = MetadataTools.createLSID("Annotation", attrIndex);
- store.setXMLAnnotationID(xml_id, attrIndex);
- } catch (JZarrException e) {
- LOGGER.warn("Failed to convert attributes to JSON");
- e.printStackTrace();
- }
- }
+ // Parse group attributes
+ if (groupKeys.isEmpty()) {
+ LOGGER.debug("ZarrReader adding group keys from ZarrService");
+ groupKeys.addAll(zarr.metadataFromGroup("0").keySet());
}
- }
-
- // Parse array attributes
- generateArrayKeys(attr, canonicalPath);
- if (arrayPaths.isEmpty()) {
- LOGGER.debug("ZarrReader adding Array Keys from ZarrService");
- arrayPaths.addAll(zarrService.getArrayKeys(canonicalPath));
- }
- orderArrayPaths(zarrRootPath);
- if (saveAnnotations()) {
- for (String key: arrayPaths) {
- Map attributes = zarrService.getArrayAttr(zarrRootPath+File.separator+key);
+ List orderedGroupKeys = reorderGroupKeys(groupKeys, omeSeriesOrder);
+ for (String key : orderedGroupKeys) {
+ Map attributes = zarr.metadataFromGroup(key);
if (attributes != null && !attributes.isEmpty()) {
+ parseResolutionCount(key, attributes);
+ parseLabels(attributes);
+ parseImageLabels(attributes);
attrIndex++;
- String jsonAttr;
- try {
- jsonAttr = ZarrUtils.toJson(attributes, true);
- store.setXMLAnnotationValue(jsonAttr, attrIndex);
- String xml_id = MetadataTools.createLSID("Annotation", attrIndex);
- store.setXMLAnnotationID(xml_id, attrIndex);
- } catch (JZarrException e) {
- LOGGER.warn("Failed to convert attributes to JSON");
- e.printStackTrace();
- }
}
}
+
+ // Parse array attributes
+ generateArrayKeys(attr);
+ if (arrayPaths.isEmpty()) {
+ LOGGER.debug("ZarrReader adding Array Keys from ZarrService");
+ arrayPaths.addAll(zarr.metadataFromArray("0").keySet());
+ }
+ orderArrayPaths();
}
core.clear();
@@ -352,8 +322,8 @@ protected void initFile(String id) throws FormatException, IOException {
store.setImageName(arrayPaths.get(seriesToCoreIndex(i)), i);
store.setImageID(MetadataTools.createLSID("Image", i), i);
}
- parsePlate(attr, zarrRootPath, "", store);
setSeries(0);
+ parsePlate(attr, "", store);
LOGGER.debug("ZarrReader initialization complete");
}
@@ -456,16 +426,16 @@ private static int[] getOriginalShape(int [] shape5D, int size) {
@Override
public void reopenFile() throws IOException {
try {
- String canonicalPath = new Location(currentId).getCanonicalPath();
- initializeZarrService();
+ ZarrLocation zarr = new ZarrLocation(currentId);
+ initializeZarrService(zarr);
}
- catch (FormatException e) {
+ catch (Exception e) {
throw new IOException(e);
}
}
- protected void initializeZarrService() throws IOException, FormatException {
- zarrService = new JZarrServiceImpl(altStore());
+ protected void initializeZarrService(ZarrLocation zarr) throws IOException, FormatException {
+ zarrService = new JZarrServiceImpl(zarr);
openZarr();
}
@@ -567,18 +537,14 @@ public void setResolution(int no, boolean openZarr) {
private void openZarr() {
try {
if (currentId != null && zarrService != null) {
- String zarrRootPath = currentId.substring(0, currentId.indexOf(".zarr")+5);
- String newZarrPath = zarrRootPath;
if (arrayPaths != null && !arrayPaths.isEmpty()) {
int seriesIndex = seriesToCoreIndex(series);
if (!hasFlattenedResolutions()) {
seriesIndex += resolution;
}
if (seriesIndex != currentOpenZarr) {
- newZarrPath += File.separator + arrayPaths.get(seriesIndex);
- String canonicalPath = new Location(newZarrPath).getCanonicalPath();
- LOGGER.debug("Opening zarr for series {} at path: {}", seriesIndex, canonicalPath);
- zarrService.open(canonicalPath);
+ LOGGER.debug("Opening zarr for series {} at path: {}", seriesIndex, arrayPaths.get(seriesIndex));
+ zarrService.open(arrayPaths.get(seriesIndex));
currentOpenZarr = seriesIndex;
}
}
@@ -588,7 +554,7 @@ private void openZarr() {
}
}
- private void orderArrayPaths(String root) {
+ private void orderArrayPaths() {
for (int i = 0; i < resSeries.size(); i++) {
for (String arrayPath: resSeries.get(i)) {
arrayPaths.remove(arrayPath);
@@ -601,7 +567,7 @@ private void orderArrayPaths(String root) {
}
}
- private void parseResolutionCount(String root, String key, Map attr) throws IOException, FormatException {
+ private void parseResolutionCount(String key, Map attr) throws IOException, FormatException {
ArrayList
+ */
+public class ZarrLocation {
+
+ /** The underlying store handle for accessing Zarr data */
+ StoreHandle store;
+
+ /** The full path to the Zarr store including the .zarr extension */
+ String path;
+
+ /** The name of the Zarr (typically the .zarr directory name) */
+ String name;
+
+ /**
+ * Constructs a ZarrLocation from the given path.
+ *
+ * The path must contain a .zarr extension. The constructor automatically detects
+ * the storage backend based on the URI scheme and initializes the appropriate store.
+ *
+ *
+ * For S3 URIs, authentication parameters can be provided as query parameters:
+ *
+ *
anonymous - Use anonymous access
+ *
accessKeyId and secretAccessKey - Use basic credentials
+ *
region - Specify AWS region (defaults to US_EAST_1)
+ *
+ * Example: s3://host/bucket/path/data.zarr?anonymous=true
+ *
+ *
+ * @param orgPath the path to the Zarr store, must contain .zarr extension
+ * @throws URISyntaxException if the path is not a valid URI
+ * @throws IllegalArgumentException if the path does not contain .zarr or uses an unsupported URI scheme
+ */
+ public ZarrLocation(final String orgPath) throws URISyntaxException, IllegalArgumentException {
+ int i = orgPath.lastIndexOf(".zarr");
+ if (i > 0) {
+ this.path = orgPath.substring(0, i+5);
+ } else {
+ throw new IllegalArgumentException("Path is not a .zarr");
+ }
+
+ URI uri = new URI(path);
+ if (uri.getScheme() == null || uri.getScheme().equals("file")) {
+ int sep = path.lastIndexOf(File.separator);
+ name = path.substring(sep + 1);
+ String storePath = path.substring(0, sep);
+ store = new FilesystemStore(storePath).resolve(name);
+ } else if (uri.getScheme().startsWith("http")) {
+ int sep = path.lastIndexOf("/");
+ name = path.substring(sep + 1);
+ String storePath = path.substring(0, sep);
+ store = new HttpStore(storePath).resolve(name);
+ } else if (uri.getScheme().startsWith("s3")) {
+ String[] tmp = path.replaceFirst("s3://", "").split("/");
+ String host = tmp[0];
+ String bucket = tmp[1];
+ name = tmp[tmp.length - 1];
+ String[] rest = Arrays.copyOfRange(tmp, 2, tmp.length);
+
+ // Extract URL parameters for authentication
+ Map params = new HashMap<>();
+ String query = (new URI(orgPath)).getQuery();
+ if (query != null) {
+ String[] pairs = query.split("&");
+ for (String pair : pairs) {
+ int idx = pair.indexOf("=");
+ if (idx > 0) {
+ params.put(pair.substring(0, idx), pair.substring(idx + 1));
+ }
+ }
+ }
+
+ URI endpoint = new URI("https://" + host);
+ S3ClientBuilder clientBuilder = S3Client.builder()
+ .endpointOverride(endpoint)
+ .region(Region.US_EAST_1); // Default region required even for non-AWS
+
+ S3Configuration s3Config = S3Configuration.builder()
+ .pathStyleAccessEnabled(true)
+ .build();
+ clientBuilder.serviceConfiguration(s3Config);
+
+ if (params.containsKey("anonymous")) {
+ clientBuilder.credentialsProvider(AnonymousCredentialsProvider.create());
+ } else if (params.containsKey("accessKeyId") && params.containsKey("secretAccessKey")) {
+ AwsBasicCredentials credentials = AwsBasicCredentials.create(
+ params.get("accessKeyId"),
+ params.get("secretAccessKey"));
+ clientBuilder.credentialsProvider(StaticCredentialsProvider.create(credentials));
+ }
+ if (params.containsKey("region")) {
+ clientBuilder.region(Region.of(params.get("region")));
+ }
+
+ S3Client client = clientBuilder.build();
+ store = new S3Store(client, bucket, null).resolve(rest);
+ } else {
+ throw new IllegalArgumentException("Unsupported URI scheme: " + uri.getScheme());
+ }
+ }
+
+ /**
+ * Opens and returns a Zarr group at the specified path.
+ *
+ * @param path the relative path to the group within the store (empty string for root group)
+ * @return the opened Group object
+ * @throws IOException if the group cannot be opened or does not exist
+ */
+ public Group getGroup(String path) throws IOException {
+ try {
+ if (path.isEmpty()) {
+ return (Group) Node.open(store);
+ } else {
+ return (Group) Node.open(store.resolve(path.split("/")));
+ }
+ } catch (Exception e) {
+ throw new IOException("Failed to open group at path: "+store+" / " + path, e);
+ }
+ }
+
+ /**
+ * Opens and returns a Zarr array at the specified path.
+ *
+ * @param path the relative path to the array within the store (empty string for root array)
+ * @return the opened Array object
+ * @throws IOException if the array cannot be opened or does not exist
+ */
+ public Array getArray(String path) throws IOException {
+ try {
+ if (path.isEmpty()) {
+ return (Array) Node.open(store);
+ } else {
+ return (Array) Node.open(store.resolve(path.split("/")));
+ }
+ } catch (Exception e) {
+ throw new IOException("Failed to open array at path: "+store+" / " + path, e);
+ }
+ }
+
+ /**
+ * Retrieves metadata from a Zarr array at the specified path.
+ *
+ * @param path the relative path to the array within the store
+ * @return a map containing metadata including shape, chunkShape, dataType, and littleEndian
+ * @throws RuntimeException if the array cannot be accessed or metadata cannot be retrieved
+ */
+ public Map metadataFromArray(String path) {
+ try {
+ Array array = getArray(path);
+ return metadataFromArray(array);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to get array metadata from path: "+store+" / " + path, e);
+ }
+ }
+
+ /**
+ * Extracts metadata from a Zarr array object.
+ *
+ * The returned map contains:
+ *
+ *
shape - The dimensions of the array
+ *
chunkShape - The chunk dimensions
+ *
dataType - The data type of array elements
+ *
littleEndian - Byte order (Todo: currently always true for v3 arrays)
+ *
+ *
+ *
+ * @param array the Array object to extract metadata from
+ * @return a map containing the array metadata
+ */
+ public Map metadataFromArray(Array array) {
+ Map res = new HashMap<>();
+ ArrayMetadata m = array.metadata();
+ if (array instanceof dev.zarr.zarrjava.v3.Array) {
+ // TODO: Implement!!
+ res.put("littleEndian", true);
+ } else {
+ dev.zarr.zarrjava.v2.ArrayMetadata m2 = (dev.zarr.zarrjava.v2.ArrayMetadata) m;
+ res.put("littleEndian", m2.endianness.equals(Endianness.LITTLE));
+ }
+ res.put("shape", m.shape);
+ res.put("chunkShape", m.chunkShape());
+ res.put("dataType", m.dataType());
+ return res;
+ }
+
+ /**
+ * Retrieves metadata from a Zarr group at the specified path.
+ *
+ * @param path the relative path to the group within the store
+ * @return a map containing the group's attributes
+ * @throws RuntimeException if the group cannot be accessed or metadata cannot be retrieved
+ */
+ public Map metadataFromGroup(String path) {
+ try {
+ Group group = getGroup(path);
+ return metadataFromGroup(group);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to get group metadata from path: "+store+" / " + path, e);
+ }
+ }
+
+ /**
+ * Extracts metadata attributes from a Zarr group object.
+ *
+ * This method handles both Zarr v2 and v3 group formats.
+ *
+ *
+ * @param group the Group object to extract metadata from
+ * @return a map containing the group's attributes
+ */
+ public Map metadataFromGroup(Group group) {
+ if (group instanceof dev.zarr.zarrjava.v2.Group) {
+ dev.zarr.zarrjava.v2.GroupMetadata m = ((dev.zarr.zarrjava.v2.Group) group).metadata;
+ return m.attributes;
+ } else {
+ dev.zarr.zarrjava.v3.GroupMetadata m = ((dev.zarr.zarrjava.v3.Group) group).metadata;
+ return m.attributes;
+ }
+ }
+
+ /**
+ * Returns the underlying store handle.
+ *
+ * @return the StoreHandle for this Zarr location
+ */
+ public StoreHandle getStoreHandle() {
+ return store;
+ }
+
+ /**
+ * Returns the name of the Zarr.
+ *
+ * @return the name (typically the .zarr directory name)
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the full path to the Zarr.
+ *
+ * @return the complete path including the .zarr extension
+ */
+ public String getPath() {
+ return path;
+ }
+}
diff --git a/src/loci/formats/services/ZarrService.java b/src/loci/formats/services/ZarrService.java
index 13b6c3a..a29a511 100644
--- a/src/loci/formats/services/ZarrService.java
+++ b/src/loci/formats/services/ZarrService.java
@@ -30,21 +30,10 @@
*/
import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-
import loci.common.services.Service;
import loci.formats.FormatException;
-import loci.formats.meta.MetadataRetrieve;
-import loci.formats.services.ZarrService.Compression;
public interface ZarrService extends Service {
-
- enum Compression {
- NONE,
- ZLIB
- }
-
/**
* Gets the text string for when Zarr implementation has not been found.
@@ -82,31 +71,9 @@ enum Compression {
*/
public Object readBytes(int [] shape, int [] offset) throws FormatException, IOException;
- /**
- * Writes values to the Zarr Array
- * @param buf values to be written in a one dimensional array
- * @param shape int array representing the shape of each dimension
- * @param x the offset for each dimension
- */
- void saveBytes(Object data, int[] shape, int[] offset) throws FormatException, IOException;
-
- public void open(String file) throws IOException, FormatException;
+ public void open(String path) throws IOException, FormatException;
boolean isLittleEndian();
boolean isOpen() throws IOException;
-
- String getID() throws IOException;
-
- public void create(String id, MetadataRetrieve meta, int[] chunks) throws IOException;
-
- void create(String id, MetadataRetrieve meta, int[] chunks, Compression compression) throws IOException;
-
- public Map getGroupAttr(String path) throws IOException, FormatException;
-
- public Map getArrayAttr(String path) throws IOException, FormatException;
-
- public Set getGroupKeys(String path) throws IOException, FormatException;
-
- public Set getArrayKeys(String path) throws IOException, FormatException;
}
diff --git a/test/loci/formats/utests/JZarrServiceImplTest.java b/test/loci/formats/utests/JZarrServiceImplTest.java
deleted file mode 100644
index 220b223..0000000
--- a/test/loci/formats/utests/JZarrServiceImplTest.java
+++ /dev/null
@@ -1,281 +0,0 @@
-package test.loci.formats.utests;
-
-/*-
- * #%L
- * Implementation of Bio-Formats readers for the next-generation file formats
- * %%
- * Copyright (C) 2020 - 2022 Open Microscopy Environment
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.nio.ByteOrder;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.mockito.Mock;
-import org.mockito.MockedStatic;
-import org.mockito.Mockito;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import com.bc.zarr.DataType;
-import com.bc.zarr.ZarrArray;
-import com.bc.zarr.ZarrGroup;
-
-import loci.formats.FormatException;
-import loci.formats.FormatTools;
-import loci.formats.services.JZarrServiceImpl;
-import ucar.ma2.InvalidRangeException;
-
-public class JZarrServiceImplTest {
-
- JZarrServiceImpl jzarrService;
- String testID = "testID";
- private static MockedStatic zarrGroupStatic;
- private static MockedStatic zarrArrayStatic;
-
- @Mock
- ZarrArray zarrArray;
-
- @Mock
- ZarrGroup zarrGroup;
-
- @BeforeMethod
- public void setup() {
- jzarrService = new JZarrServiceImpl(null);
- zarrArray = Mockito.mock(ZarrArray.class);
- zarrGroup = Mockito.mock(ZarrGroup.class);
- jzarrService.open(testID, zarrArray);
-
- zarrGroupStatic = Mockito.mockStatic(ZarrGroup.class);
- zarrGroupStatic.when(() -> ZarrGroup.open("path")).thenReturn(zarrGroup);
-
- zarrArrayStatic = Mockito.mockStatic(ZarrArray.class);
- zarrArrayStatic.when(() -> ZarrArray.open("path")).thenReturn(zarrArray);
- }
-
- @AfterMethod
- public void teardown() {
- try {
- jzarrService.close();
- zarrGroupStatic.close();
- zarrArrayStatic.close();
- } catch (IOException e) {
- fail("IOException thrown while closing JZarrServiceImpl");
- }
- }
-
- @DataProvider(name = "pixelTypes")
- public Object[][] createPixelTypes() {
- return new Object[][] {
- {FormatTools.INT8, DataType.i1},
- {FormatTools.INT16, DataType.i2},
- {FormatTools.INT32, DataType.i4},
- {FormatTools.UINT8, DataType.u1},
- {FormatTools.UINT16, DataType.u2},
- {FormatTools.UINT32, DataType.u4},
- {FormatTools.FLOAT, DataType.f4},
- {FormatTools.DOUBLE, DataType.f8},
- };
- }
-
- @Test(dataProvider = "pixelTypes")
- public void testZarrPixelType(int omePixelType, DataType jzarrPixelType) {
- assertEquals(jzarrPixelType, jzarrService.getZarrPixelType(omePixelType));
- }
-
- @Test(dataProvider = "pixelTypes")
- public void testOMEPixelType(int omePixelType, DataType jzarrPixelType) {
- assertEquals(omePixelType, jzarrService.getOMEPixelType(jzarrPixelType));
- }
-
- @Test(dataProvider = "pixelTypes")
- public void testPixelType(int omePixelType, DataType jzarrPixelType) {
- when(zarrArray.getDataType()).thenReturn(jzarrPixelType);
- assertEquals(omePixelType, jzarrService.getPixelType());
- }
-
- @Test
- public void testIsLittleEndian() {
- when(zarrArray.getByteOrder()).thenReturn(ByteOrder.BIG_ENDIAN);
- assertEquals(false, jzarrService.isLittleEndian());
- when(zarrArray.getByteOrder()).thenReturn(ByteOrder.LITTLE_ENDIAN);
- assertEquals(true, jzarrService.isLittleEndian());
- }
-
- @Test
- public void testGetNoZarrMessage() {
- assertEquals(JZarrServiceImpl.NO_ZARR_MSG, jzarrService.getNoZarrMsg());
- }
-
- @Test
- public void testGetShape() {
- int[] expectedShape = {1024, 1024, 32, 32, 32};
- when(zarrArray.getShape()).thenReturn(expectedShape);
- assertEquals(expectedShape, jzarrService.getShape());
- }
-
- @Test
- public void testGetChunkSize() {
- int[] expectedChunks = {256, 256, 8, 8, 8};
- when(zarrArray.getChunks()).thenReturn(expectedChunks);
- assertEquals(expectedChunks, jzarrService.getChunkSize());
- }
-
- @Test
- public void testGetGroupAttributes() {
- Map emptyAttributes = new HashMap();
- Map attributes = new HashMap();
- attributes.put("AttributeKey1", "AttributeValue1");
- attributes.put("AttributeKey2", "AttributeValue2");
-
- try {
- assertEquals(jzarrService.getGroupAttr("path"), emptyAttributes);
- when(zarrGroup.getAttributes()).thenReturn(attributes);
- assertEquals(jzarrService.getGroupAttr("path"), attributes);
- } catch (IOException | FormatException e) {
- fail("Unexpected exception thrown while retrieving group attributes");
- e.printStackTrace();
- }
- }
-
- @Test
- public void testGetGroupKeys() {
- Set emptyKeys = new HashSet();
- Set keys = new HashSet();
- keys.add("Key1");
- keys.add("Key2");
-
- try {
- assertEquals(jzarrService.getGroupKeys("path"), emptyKeys);
- when(zarrGroup.getGroupKeys()).thenReturn(keys);
- assertEquals(jzarrService.getGroupKeys("path"), keys);
- } catch (IOException | FormatException e) {
- fail("Unexpected exception thrown while retrieving group keys");
- e.printStackTrace();
- }
- }
-
- @Test
- public void testGetArrayAttributes() {
- Map emptyAttributes = new HashMap();
- Map attributes = new HashMap();
- attributes.put("AttributeKey1", "AttributeValue1");
- attributes.put("AttributeKey2", "AttributeValue2");
-
- try {
- assertEquals(jzarrService.getArrayAttr("path"), emptyAttributes);
- when(zarrArray.getAttributes()).thenReturn(attributes);
- assertEquals(jzarrService.getArrayAttr("path"), attributes);
- } catch (IOException | FormatException e) {
- fail("Unexpected exception thrown while retrieving array attributes");
- e.printStackTrace();
- }
- }
-
- @Test
- public void testGetArrayKeys() {
- Set emptyKeys = new HashSet();
- Set keys = new HashSet();
- keys.add("Key1");
- keys.add("Key2");
-
- try {
- assertEquals(jzarrService.getArrayKeys("path"), emptyKeys);
- when(zarrGroup.getArrayKeys()).thenReturn(keys);
- assertEquals(jzarrService.getArrayKeys("path"), keys);
- } catch (IOException | FormatException e) {
- fail("Unexpected exception thrown while retrieving array keys");
- e.printStackTrace();
- }
- }
-
- @Test
- public void testGetID() {
- assertEquals(testID, jzarrService.getID());
- JZarrServiceImpl nullJzarrService = new JZarrServiceImpl(null);
- assertEquals(null, nullJzarrService.getID());
- nullJzarrService.open("TestGetID", zarrArray);
- assertEquals("TestGetID", nullJzarrService.getID());
- }
-
- @Test
- public void testIsOpen() {
- assertEquals(true, jzarrService.isOpen());
- JZarrServiceImpl nullJzarrService = new JZarrServiceImpl(null);
- assertEquals(false, nullJzarrService.isOpen());
- nullJzarrService.open("isOpenTestID", zarrArray);
- assertEquals(true, nullJzarrService.isOpen());
- }
-
- @Test
- public void testReadBytes() {
- int[] expectedBytes = {256, 256, 8, 8, 8};
- int[] shape = {1024, 1024, 32, 32, 32};
- int[] offset = {0, 0, 0, 0, 0};
- try {
- when(zarrArray.read(shape, offset)).thenReturn(expectedBytes);
- assertEquals(expectedBytes, jzarrService.readBytes(shape, offset));
- } catch (IOException e) {
- fail("Unexpected exception on JZarrServiceImpl readBytes");
- e.printStackTrace();
- } catch (InvalidRangeException e) {
- fail("Unexpected InvalidRangeException on ZarrArray read");
- e.printStackTrace();
- } catch (FormatException e) {
- fail("Unexpected FormatException on JZarrServiceImpl readBytes");
- e.printStackTrace();
- }
- }
-
- @Test
- public void testSaveBytes() {
- int[] data = {256, 256, 8, 8, 8};
- int[] shape = {1024, 1024, 32, 32, 32};
- int[] offset = {0, 0, 0, 0, 0};
- try {
- jzarrService.saveBytes(data, shape, offset);
- verify(zarrArray).write(data, shape, offset);
- } catch (IOException e) {
- fail("Unexpected IOException on JZarrServiceImpl saveBytes");
- e.printStackTrace();
- } catch (InvalidRangeException e) {
- fail("Unexpected InvalidRangeException on ZarrArray write");
- e.printStackTrace();
- } catch (FormatException e) {
- fail("Unexpected FormatException on JZarrServiceImpl saveBytes");
- e.printStackTrace();
- }
- }
-}
diff --git a/test/loci/formats/utests/ZarrReaderMock.java b/test/loci/formats/utests/ZarrReaderMock.java
deleted file mode 100644
index bc0cd23..0000000
--- a/test/loci/formats/utests/ZarrReaderMock.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package test.loci.formats.utests;
-
-/*-
- * #%L
- * Implementation of Bio-Formats readers for the next-generation file formats
- * %%
- * Copyright (C) 2020 - 2022 Open Microscopy Environment
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-
-import java.io.IOException;
-
-import loci.formats.FormatException;
-import loci.formats.in.ZarrReader;
-import loci.formats.services.ZarrService;
-
-public class ZarrReaderMock extends ZarrReader {
-
- private ZarrService mockService;
-
- public ZarrReaderMock(ZarrService zarrService) {
- mockService = zarrService;
- }
-
- @Override
- protected void initializeZarrService() throws IOException, FormatException {
- zarrService = mockService;
- }
-}
diff --git a/test/loci/formats/utests/ZarrReaderTest.java b/test/loci/formats/utests/ZarrReaderTest.java
deleted file mode 100644
index 7c45fe1..0000000
--- a/test/loci/formats/utests/ZarrReaderTest.java
+++ /dev/null
@@ -1,289 +0,0 @@
-package test.loci.formats.utests;
-
-/*-
- * #%L
- * Implementation of Bio-Formats readers for the next-generation file formats
- * %%
- * Copyright (C) 2020 - 2022 Open Microscopy Environment
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-
-import static org.junit.Assert.*;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertTrue;
-import static org.testng.AssertJUnit.assertFalse;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-
-import static org.mockito.Mockito.when;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import loci.common.DataTools;
-import loci.common.Location;
-import loci.formats.FormatException;
-import loci.formats.FormatTools;
-import loci.formats.in.ZarrReader;
-import loci.formats.services.ZarrService;
-
-
-/**
- * Tests the functionality of ZarrReader
- */
-public class ZarrReaderTest {
-
- @Mock
- private ZarrService zarrService;
-
- @InjectMocks
- private ZarrReaderMock reader;
-
- private File file;
- private int[] shape = {8, 16, 32, 512, 1024};
-
- @BeforeClass
- public void setUp() throws Exception {
- zarrService = Mockito.mock(ZarrService.class);
- reader = new ZarrReaderMock(zarrService);
- file = File.createTempFile("tileTest", ".zarr");
- String rootPath = file.getAbsolutePath();
- String canonicalPath = new Location(rootPath).getCanonicalPath();
-
- Map topLevelAttributes = new HashMap();
- ArrayList multiscales = new ArrayList();
- Map datasets = new HashMap();
- ArrayList multiscalePaths = new ArrayList();
- Map multiScale1 = new HashMap();
- Map multiScale2 = new HashMap();
- Map multiScale3 = new HashMap();
- multiScale1.put("path", "0");
- multiScale2.put("path", "1");
- multiScale3.put("path", "2");
- multiscalePaths.add(multiScale1);
- multiscalePaths.add(multiScale2);
- multiscalePaths.add(multiScale3);
- datasets.put("datasets", multiscalePaths);
- datasets.put("axes", Arrays.asList("t", "c", "z", "y", "x"));
- multiscales.add(datasets);
- topLevelAttributes.put("multiscales", multiscales);
-
- when(zarrService.getGroupAttr(canonicalPath)).thenReturn(topLevelAttributes);
- when(zarrService.getShape()).thenReturn(shape);
- when(zarrService.getPixelType()).thenReturn(0);
- reader.setId(file.getAbsolutePath());
- }
-
- @AfterClass
- public void tearDown() throws Exception {
- reader.close();
- file.delete();
- }
-
- @Test
- public void testIsThisType() {
- assertTrue(reader.isThisType("test/path/data.zarr", true));
- assertTrue(reader.isThisType("test/path/data.ZARR", true));
- assertTrue(reader.isThisType("test/path/data.zarr/0/0", true));
- assertTrue(reader.isThisType("test/path/data.zarr/0/0/0.0.0.0.0", true));
- assertTrue(reader.isThisType("test/path/data.zarr/0/0/.zattrs", true));
- assertFalse(reader.isThisType("test/path/data.zar", true));
- }
-
- @Test
- public void testGetOptimalTileHeight() {
- int [] expectedChunks = {8, 8, 8, 256, 128};
- when(zarrService.getChunkSize()).thenReturn(expectedChunks);
- assertEquals(expectedChunks[3], reader.getOptimalTileHeight());
- }
-
- @Test
- public void testGetOptimalTileWidth() {
- int [] expectedChunks = {8, 8, 8, 256, 128};
- when(zarrService.getChunkSize()).thenReturn(expectedChunks);
- assertEquals(expectedChunks[4], reader.getOptimalTileWidth());
- }
-
- @Test
- public void testDimensions() {
- assertEquals(shape[4], reader.getSizeX());
- assertEquals(shape[3], reader.getSizeY());
- assertEquals(shape[2], reader.getSizeZ());
- assertEquals(shape[1], reader.getSizeC());
- assertEquals(shape[0], reader.getSizeT());
- }
-
- @Test
- public void testOpenBytes() {
- int[] readerShape = {1, 1, 1, shape[3], shape[4]};
- int[] readerOffset = {0, 0, 0, 0, 0};
- int[] expectedPixelValues = new int[1024*512];
- for (int i = 0; i < expectedPixelValues.length; i++) {
- expectedPixelValues[i] = i;
- }
- byte[] buf = new byte[1024*512*4];
- byte[] expectedBuf = DataTools.intsToBytes(expectedPixelValues, false);
- try {
- when(zarrService.readBytes(readerShape, readerOffset)).thenReturn(expectedPixelValues);
- when(zarrService.getPixelType()).thenReturn(4);
- buf = reader.openBytes(0, buf);
- assertEquals(expectedBuf, buf);
-
- when(zarrService.readBytes(readerShape, readerOffset)).thenReturn(expectedBuf);
- when(zarrService.getPixelType()).thenReturn(0);
- buf = new byte[1024*512*4];
- buf = reader.openBytes(0, buf);
- assertEquals(expectedBuf, buf);
- } catch (FormatException | IOException e) {
- fail("Unexpected exception thrown while reading bytes");
- }
- }
-
- @Test
- public void testGetDomains() {
- assertEquals(FormatTools.NON_SPECIAL_DOMAINS, reader.getDomains());
- }
-
- @Test
- public void testSetSeries() {
- assertEquals(0, reader.getSeries());
- reader.setSeries(1);
- assertEquals(1, reader.getSeries());
- }
-
- @Test
- public void testResolutionCount() {
- try {
- reader.close();
- reader.setFlattenedResolutions(false);
- reader.setId(file.getAbsolutePath());
- } catch (IOException | FormatException e) {
- fail("Unexpected exception while setting flattenedResolutions");
- }
- assertEquals(3, reader.getResolutionCount());
- assertEquals(1, reader.getSeriesCount());
- try {
- reader.close();
- reader.setFlattenedResolutions(true);
- reader.setId(file.getAbsolutePath());
- } catch (IOException | FormatException e) {
- fail("Unexpected exception while setting flattenedResolutions");
- }
- assertEquals(1, reader.getResolutionCount());
- assertEquals(3, reader.getSeriesCount());
- }
-
- @Test
- public void testParseOmeroMetadataWithIntegerValues() {
- Map omeroMetadata = new HashMap<>();
- omeroMetadata.put("id", 1);
- omeroMetadata.put("name", "Test Image");
- omeroMetadata.put("version", "0.1");
-
- ArrayList channels = new ArrayList<>();
- Map channel = new HashMap<>();
- channel.put("active", true);
- channel.put("coefficient", 1);
- channel.put("color", "FFFFFF");
- channel.put("family", "linear");
- channel.put("inverted", false);
- channel.put("label", "Channel 1");
-
- Map window = new HashMap<>();
- window.put("start", 0);
- window.put("end", 255);
- window.put("min", 0);
- window.put("max", 255);
- channel.put("window", window);
-
- channels.add(channel);
- omeroMetadata.put("channels", channels);
-
- Map rdefs = new HashMap<>();
- rdefs.put("defaultT", 0);
- rdefs.put("defaultZ", 0);
- rdefs.put("model", "color");
- omeroMetadata.put("rdefs", rdefs);
-
- Map test = new HashMap<>();
- test.put("omero", omeroMetadata);
- try {
- reader.parseOmeroMetadata(test);
- } catch (IOException | FormatException e) {
- fail("Unexpected exception while parsing Omero metadata with Integer values");
- }
- }
-
- @Test
- public void testParseOmeroMetadataWithDoubleValues() {
- Map omeroMetadata = new HashMap<>();
- omeroMetadata.put("id", 1);
- omeroMetadata.put("name", "Test Image");
- omeroMetadata.put("version", "0.1");
-
- ArrayList channels = new ArrayList<>();
- Map channel = new HashMap<>();
- channel.put("active", true);
- channel.put("coefficient", 1.0);
- channel.put("color", "FFFFFF");
- channel.put("family", "linear");
- channel.put("inverted", false);
- channel.put("label", "Channel 1");
-
- Map window = new HashMap<>();
- window.put("start", 0.0);
- window.put("end", 255.0);
- window.put("min", 0.0);
- window.put("max", 255.0);
- channel.put("window", window);
-
- channels.add(channel);
- omeroMetadata.put("channels", channels);
-
- Map rdefs = new HashMap<>();
- rdefs.put("defaultT", 0);
- rdefs.put("defaultZ", 0);
- rdefs.put("model", "color");
- omeroMetadata.put("rdefs", rdefs);
-
- Map test = new HashMap<>();
- test.put("omero", omeroMetadata);
- try {
- reader.parseOmeroMetadata(test);
- } catch (IOException | FormatException e) {
- fail("Unexpected exception while parsing Omero metadata with Double values");
- }
- }
-}