Skip to content

Commit f9ee1ed

Browse files
committed
add tests for omero, bioformats2raw, labels, and hcs
1 parent 0630e56 commit f9ee1ed

39 files changed

Lines changed: 784 additions & 2 deletions

File tree

src/main/java/dev/zarr/zarrjava/ome/v0_5/MultiscaleImage.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ public MultiscalesEntry getMultiscalesEntry(int i) throws ZarrException {
8282
return omeMetadata.multiscales.get(i);
8383
}
8484

85+
@javax.annotation.Nullable
86+
public dev.zarr.zarrjava.ome.metadata.OmeroMetadata getOmeroMetadata() {
87+
return omeMetadata.omero;
88+
}
89+
90+
@javax.annotation.Nullable
91+
public Integer getBioformats2rawLayout() {
92+
return omeMetadata.bioformats2rawLayout;
93+
}
94+
8595
@Override
8696
public dev.zarr.zarrjava.core.Array openScaleLevel(int i) throws IOException, ZarrException {
8797
String path = getMultiscalesEntry(0).datasets.get(i).path;

src/test/java/dev/zarr/zarrjava/OmeZarrTest.java

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
package dev.zarr.zarrjava;
22

3+
import dev.zarr.zarrjava.core.Attributes;
34
import dev.zarr.zarrjava.ome.MultiscaleImage;
45
import dev.zarr.zarrjava.ome.MultiscalesMetadataImage;
6+
import dev.zarr.zarrjava.ome.Plate;
57
import dev.zarr.zarrjava.ome.UnifiedMultiscaleNode;
68
import dev.zarr.zarrjava.ome.UnifiedSinglescaleNode;
9+
import dev.zarr.zarrjava.ome.Well;
710
import dev.zarr.zarrjava.ome.metadata.Axis;
811
import dev.zarr.zarrjava.ome.metadata.CoordinateTransformation;
912
import dev.zarr.zarrjava.ome.metadata.MultiscalesEntry;
13+
import dev.zarr.zarrjava.ome.metadata.NamedEntry;
14+
import dev.zarr.zarrjava.ome.metadata.OmeroMetadata;
15+
import dev.zarr.zarrjava.ome.metadata.PlateMetadata;
16+
import dev.zarr.zarrjava.ome.metadata.WellImage;
17+
import dev.zarr.zarrjava.ome.metadata.WellMetadata;
18+
import dev.zarr.zarrjava.ome.metadata.WellRef;
1019
import dev.zarr.zarrjava.store.FilesystemStore;
1120
import dev.zarr.zarrjava.store.StoreHandle;
1221
import dev.zarr.zarrjava.v3.Array;
@@ -15,7 +24,9 @@
1524

1625
import java.util.Arrays;
1726
import java.util.Collections;
27+
import java.util.HashMap;
1828
import java.util.List;
29+
import java.util.Map;
1930

2031
import static org.junit.jupiter.api.Assertions.*;
2132

@@ -202,4 +213,270 @@ void readV04_entryHasVersion() throws Exception {
202213
MultiscalesEntry entry = image.getMultiscalesEntry(0);
203214
assertEquals("0.4", entry.version);
204215
}
216+
217+
// ── Omero + bioformats2raw.layout (read from testdata) ──────────────────
218+
219+
@Test
220+
void readV05_omero() throws Exception {
221+
dev.zarr.zarrjava.ome.v0_5.MultiscaleImage image =
222+
dev.zarr.zarrjava.ome.v0_5.MultiscaleImage.openMultiscaleImage(
223+
storeHandle(TESTDATA.resolve("ome/v0.5")));
224+
225+
OmeroMetadata omero = image.getOmeroMetadata();
226+
assertNotNull(omero);
227+
assertEquals(2, omero.channels.size());
228+
assertEquals("DAPI", omero.channels.get(0).get("label"));
229+
assertEquals("GFP", omero.channels.get(1).get("label"));
230+
assertEquals("color", omero.rdefs.get("model"));
231+
}
232+
233+
@Test
234+
void readV04_omero() throws Exception {
235+
dev.zarr.zarrjava.ome.v0_4.MultiscaleImage image =
236+
dev.zarr.zarrjava.ome.v0_4.MultiscaleImage.openMultiscaleImage(
237+
storeHandle(TESTDATA.resolve("ome/v0.4")));
238+
239+
OmeroMetadata omero = image.getOmeroMetadata();
240+
assertNotNull(omero);
241+
assertEquals(2, omero.channels.size());
242+
assertEquals("DAPI", omero.channels.get(0).get("label"));
243+
assertEquals("color", omero.rdefs.get("model"));
244+
}
245+
246+
@Test
247+
void readV05_bioformats2rawLayout() throws Exception {
248+
dev.zarr.zarrjava.ome.v0_5.MultiscaleImage image =
249+
dev.zarr.zarrjava.ome.v0_5.MultiscaleImage.openMultiscaleImage(
250+
storeHandle(TESTDATA.resolve("ome/v0.5")));
251+
assertEquals(Integer.valueOf(3), image.getBioformats2rawLayout());
252+
}
253+
254+
@Test
255+
void readV04_bioformats2rawLayout() throws Exception {
256+
dev.zarr.zarrjava.ome.v0_4.MultiscaleImage image =
257+
dev.zarr.zarrjava.ome.v0_4.MultiscaleImage.openMultiscaleImage(
258+
storeHandle(TESTDATA.resolve("ome/v0.4")));
259+
assertEquals(Integer.valueOf(3), image.getBioformats2rawLayout());
260+
}
261+
262+
// ── Labels (read from testdata) ──────────────────────────────────────────
263+
264+
@Test
265+
void readV05_labels() throws Exception {
266+
MultiscaleImage image = MultiscaleImage.open(storeHandle(TESTDATA.resolve("ome/v0.5")));
267+
268+
List<String> labels = image.getLabels();
269+
assertEquals(Collections.singletonList("nuclei"), labels);
270+
271+
MultiscaleImage nuclei = image.openLabel("nuclei");
272+
assertInstanceOf(dev.zarr.zarrjava.ome.v0_5.MultiscaleImage.class, nuclei);
273+
assertEquals(Arrays.asList("z", "y", "x"), nuclei.getAxisNames());
274+
}
275+
276+
@Test
277+
void readV04_labels() throws Exception {
278+
MultiscaleImage image = MultiscaleImage.open(storeHandle(TESTDATA.resolve("ome/v0.4")));
279+
280+
List<String> labels = image.getLabels();
281+
assertEquals(Collections.singletonList("nuclei"), labels);
282+
283+
MultiscaleImage nuclei = image.openLabel("nuclei");
284+
assertInstanceOf(dev.zarr.zarrjava.ome.v0_4.MultiscaleImage.class, nuclei);
285+
assertEquals(Arrays.asList("z", "y", "x"), nuclei.getAxisNames());
286+
}
287+
288+
// ── HCS Plate (read from testdata) ───────────────────────────────────────
289+
290+
@Test
291+
void readV05_plate() throws Exception {
292+
Plate plate = Plate.open(storeHandle(TESTDATA.resolve("ome/v0.5_hcs")));
293+
assertInstanceOf(dev.zarr.zarrjava.ome.v0_5.Plate.class, plate);
294+
295+
PlateMetadata meta = plate.getPlateMetadata();
296+
assertEquals(2, meta.columns.size());
297+
assertEquals(2, meta.rows.size());
298+
assertEquals("A", meta.rows.get(0).name);
299+
assertEquals("1", meta.columns.get(0).name);
300+
assertEquals("A/1", meta.wells.get(0).path);
301+
}
302+
303+
@Test
304+
void readV04_plate() throws Exception {
305+
Plate plate = Plate.open(storeHandle(TESTDATA.resolve("ome/v0.4_hcs")));
306+
assertInstanceOf(dev.zarr.zarrjava.ome.v0_4.Plate.class, plate);
307+
308+
PlateMetadata meta = plate.getPlateMetadata();
309+
assertEquals(2, meta.columns.size());
310+
assertEquals("A", meta.rows.get(0).name);
311+
assertEquals("A/1", meta.wells.get(0).path);
312+
}
313+
314+
@Test
315+
void readV05_wellViaPlate() throws Exception {
316+
Plate plate = Plate.open(storeHandle(TESTDATA.resolve("ome/v0.5_hcs")));
317+
Well well = plate.openWell("A/1");
318+
assertInstanceOf(dev.zarr.zarrjava.ome.v0_5.Well.class, well);
319+
320+
assertEquals(1, well.getWellMetadata().images.size());
321+
assertEquals("0", well.getWellMetadata().images.get(0).path);
322+
assertEquals(Integer.valueOf(0), well.getWellMetadata().images.get(0).acquisition);
323+
}
324+
325+
@Test
326+
void readV04_wellViaPlate() throws Exception {
327+
Plate plate = Plate.open(storeHandle(TESTDATA.resolve("ome/v0.4_hcs")));
328+
Well well = plate.openWell("A/1");
329+
assertInstanceOf(dev.zarr.zarrjava.ome.v0_4.Well.class, well);
330+
331+
assertEquals(1, well.getWellMetadata().images.size());
332+
assertEquals("0", well.getWellMetadata().images.get(0).path);
333+
}
334+
335+
@Test
336+
void readV05_hcsFullNavigation() throws Exception {
337+
Plate plate = Plate.open(storeHandle(TESTDATA.resolve("ome/v0.5_hcs")));
338+
Well well = plate.openWell("A/1");
339+
MultiscaleImage fov = well.openImage("0");
340+
341+
assertInstanceOf(dev.zarr.zarrjava.ome.v0_5.MultiscaleImage.class, fov);
342+
assertEquals(Arrays.asList("t", "c", "z", "y", "x"), fov.getAxisNames());
343+
}
344+
345+
@Test
346+
void readV04_hcsFullNavigation() throws Exception {
347+
Plate plate = Plate.open(storeHandle(TESTDATA.resolve("ome/v0.4_hcs")));
348+
Well well = plate.openWell("A/1");
349+
MultiscaleImage fov = well.openImage("0");
350+
351+
assertInstanceOf(dev.zarr.zarrjava.ome.v0_4.MultiscaleImage.class, fov);
352+
assertEquals(Arrays.asList("t", "c", "z", "y", "x"), fov.getAxisNames());
353+
}
354+
355+
// ── Omero write round-trip (v0.4) ────────────────────────────────────────
356+
357+
@Test
358+
void writeV04_omeroRoundTrip() throws Exception {
359+
List<Axis> axes = Arrays.asList(
360+
new Axis("z", "space", "micrometer"),
361+
new Axis("y", "space", "micrometer")
362+
);
363+
MultiscalesEntry entry = new MultiscalesEntry(axes, Collections.emptyList());
364+
365+
StoreHandle handle = storeHandle(TESTOUTPUT.resolve("ome_v04_omero"));
366+
dev.zarr.zarrjava.ome.v0_4.MultiscaleImage created =
367+
dev.zarr.zarrjava.ome.v0_4.MultiscaleImage.create(handle, entry);
368+
369+
dev.zarr.zarrjava.v2.ArrayMetadata arrayMetadata = new dev.zarr.zarrjava.v2.ArrayMetadata(
370+
2, new long[]{16, 16}, new int[]{16, 16},
371+
dev.zarr.zarrjava.v2.DataType.FLOAT32, 0,
372+
dev.zarr.zarrjava.v2.Order.C, null, null, null);
373+
created.createScaleLevel("0", arrayMetadata,
374+
Collections.singletonList(CoordinateTransformation.scale(Arrays.asList(1.0, 1.0))));
375+
376+
Map<String, Object> channelMap = new HashMap<String, Object>();
377+
channelMap.put("label", "DAPI");
378+
channelMap.put("color", "0000FF");
379+
Map<String, Object> rdefsMap = new HashMap<String, Object>();
380+
rdefsMap.put("model", "color");
381+
OmeroMetadata omero = new OmeroMetadata(Collections.singletonList(channelMap), rdefsMap);
382+
created.setOmeroMetadata(omero);
383+
384+
dev.zarr.zarrjava.ome.v0_4.MultiscaleImage reopened =
385+
dev.zarr.zarrjava.ome.v0_4.MultiscaleImage.openMultiscaleImage(handle);
386+
OmeroMetadata got = reopened.getOmeroMetadata();
387+
assertNotNull(got);
388+
assertEquals("DAPI", got.channels.get(0).get("label"));
389+
assertEquals("color", got.rdefs.get("model"));
390+
}
391+
392+
// ── Labels write round-trip (v0.5) ───────────────────────────────────────
393+
394+
@Test
395+
void writeV05_labelsRoundTrip() throws Exception {
396+
List<Axis> axes = Arrays.asList(
397+
new Axis("z", "space", "micrometer"),
398+
new Axis("y", "space", "micrometer")
399+
);
400+
StoreHandle handle = storeHandle(TESTOUTPUT.resolve("ome_v05_labels"));
401+
dev.zarr.zarrjava.ome.v0_5.MultiscaleImage parent =
402+
dev.zarr.zarrjava.ome.v0_5.MultiscaleImage.create(handle, new MultiscalesEntry(axes, Collections.emptyList()));
403+
404+
Attributes labelsAttrs = new Attributes();
405+
labelsAttrs.put("labels", Arrays.asList("nuclei"));
406+
dev.zarr.zarrjava.v3.Group.create(handle.resolve("labels"), labelsAttrs);
407+
408+
dev.zarr.zarrjava.ome.v0_5.MultiscaleImage nuclei =
409+
dev.zarr.zarrjava.ome.v0_5.MultiscaleImage.create(
410+
handle.resolve("labels").resolve("nuclei"),
411+
new MultiscalesEntry(axes, Collections.emptyList()));
412+
nuclei.createScaleLevel("0",
413+
Array.metadataBuilder().withShape(16, 16).withChunkShape(16, 16).withDataType(DataType.UINT8).build(),
414+
Collections.singletonList(CoordinateTransformation.scale(Arrays.asList(1.0, 1.0))));
415+
416+
MultiscaleImage reopened = MultiscaleImage.open(handle);
417+
assertEquals(Collections.singletonList("nuclei"), reopened.getLabels());
418+
assertEquals(Arrays.asList("z", "y"), reopened.openLabel("nuclei").getAxisNames());
419+
}
420+
421+
// ── HCS write round-trips ────────────────────────────────────────────────
422+
423+
@Test
424+
void writeV05_plateRoundTrip() throws Exception {
425+
PlateMetadata plateMetadata = new PlateMetadata(
426+
Arrays.asList(new NamedEntry("1"), new NamedEntry("2")),
427+
Arrays.asList(new NamedEntry("A"), new NamedEntry("B")),
428+
Collections.singletonList(new WellRef("A/1", 0, 0)),
429+
null, null, null, null);
430+
431+
StoreHandle handle = storeHandle(TESTOUTPUT.resolve("ome_v05_plate"));
432+
dev.zarr.zarrjava.ome.v0_5.Plate.createPlate(handle, plateMetadata);
433+
434+
Plate reopened = Plate.open(handle);
435+
assertEquals(2, reopened.getPlateMetadata().columns.size());
436+
assertEquals("A", reopened.getPlateMetadata().rows.get(0).name);
437+
assertEquals("A/1", reopened.getPlateMetadata().wells.get(0).path);
438+
}
439+
440+
@Test
441+
void writeV04_plateRoundTrip() throws Exception {
442+
PlateMetadata plateMetadata = new PlateMetadata(
443+
Arrays.asList(new NamedEntry("1"), new NamedEntry("2")),
444+
Arrays.asList(new NamedEntry("A"), new NamedEntry("B")),
445+
Collections.singletonList(new WellRef("A/1", 0, 0)),
446+
null, null, null, null);
447+
448+
StoreHandle handle = storeHandle(TESTOUTPUT.resolve("ome_v04_plate"));
449+
dev.zarr.zarrjava.ome.v0_4.Plate.createPlate(handle, plateMetadata);
450+
451+
Plate reopened = Plate.open(handle);
452+
assertEquals(2, reopened.getPlateMetadata().columns.size());
453+
assertEquals("A/1", reopened.getPlateMetadata().wells.get(0).path);
454+
}
455+
456+
@Test
457+
void writeV05_hcsFullIntegration() throws Exception {
458+
StoreHandle plateHandle = storeHandle(TESTOUTPUT.resolve("ome_v05_hcs_full"));
459+
460+
dev.zarr.zarrjava.ome.v0_5.Plate.createPlate(plateHandle, new PlateMetadata(
461+
Collections.singletonList(new NamedEntry("1")),
462+
Collections.singletonList(new NamedEntry("A")),
463+
Collections.singletonList(new WellRef("A/1", 0, 0)),
464+
null, null, null, null));
465+
466+
dev.zarr.zarrjava.ome.v0_5.Well.createWell(
467+
plateHandle.resolve("A/1"),
468+
new WellMetadata(Collections.singletonList(new WellImage("0", null))));
469+
470+
List<Axis> axes = Arrays.asList(new Axis("z", "space", "micrometer"), new Axis("y", "space", "micrometer"));
471+
dev.zarr.zarrjava.ome.v0_5.MultiscaleImage fov = dev.zarr.zarrjava.ome.v0_5.MultiscaleImage.create(
472+
plateHandle.resolve("A/1").resolve("0"),
473+
new MultiscalesEntry(axes, Collections.emptyList()));
474+
fov.createScaleLevel("0",
475+
Array.metadataBuilder().withShape(16, 16).withChunkShape(16, 16).withDataType(DataType.FLOAT32).build(),
476+
Collections.singletonList(CoordinateTransformation.scale(Arrays.asList(1.0, 1.0))));
477+
478+
MultiscaleImage image = Plate.open(plateHandle).openWell("A/1").openImage("0");
479+
assertInstanceOf(dev.zarr.zarrjava.ome.v0_5.MultiscaleImage.class, image);
480+
assertEquals(Arrays.asList("z", "y"), image.getAxisNames());
481+
}
205482
}

testdata/ome/v0.4/.zattrs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,21 @@
7575
],
7676
"type": "gaussian"
7777
}
78-
]
78+
],
79+
"omero": {
80+
"channels": [
81+
{
82+
"label": "DAPI",
83+
"color": "0000FF"
84+
},
85+
{
86+
"label": "GFP",
87+
"color": "00FF00"
88+
}
89+
],
90+
"rdefs": {
91+
"model": "color"
92+
}
93+
},
94+
"bioformats2raw.layout": 3
7995
}

testdata/ome/v0.4/0/0.0.0.0.0

34 Bytes
Binary file not shown.

testdata/ome/v0.4/0/0.1.0.0.0

15 Bytes
Binary file not shown.

testdata/ome/v0.4/1/0.0.0.0.0

-9 Bytes
Binary file not shown.

testdata/ome/v0.4/1/0.1.0.0.0

19 Bytes
Binary file not shown.

testdata/ome/v0.4/labels/.zattrs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"labels": [
3+
"nuclei"
4+
]
5+
}

testdata/ome/v0.4/labels/.zgroup

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"zarr_format": 2
3+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"multiscales": [
3+
{
4+
"version": "0.4",
5+
"name": "nuclei",
6+
"axes": [
7+
{
8+
"name": "z",
9+
"type": "space",
10+
"unit": "micrometer"
11+
},
12+
{
13+
"name": "y",
14+
"type": "space",
15+
"unit": "micrometer"
16+
},
17+
{
18+
"name": "x",
19+
"type": "space",
20+
"unit": "micrometer"
21+
}
22+
],
23+
"datasets": [
24+
{
25+
"path": "0",
26+
"coordinateTransformations": [
27+
{
28+
"type": "scale",
29+
"scale": [
30+
0.5,
31+
0.5,
32+
0.5
33+
]
34+
}
35+
]
36+
}
37+
]
38+
}
39+
]
40+
}

0 commit comments

Comments
 (0)