|
1 | 1 | package dev.zarr.zarrjava; |
2 | 2 |
|
| 3 | +import dev.zarr.zarrjava.core.Attributes; |
3 | 4 | import dev.zarr.zarrjava.ome.MultiscaleImage; |
4 | 5 | import dev.zarr.zarrjava.ome.MultiscalesMetadataImage; |
| 6 | +import dev.zarr.zarrjava.ome.Plate; |
5 | 7 | import dev.zarr.zarrjava.ome.UnifiedMultiscaleNode; |
6 | 8 | import dev.zarr.zarrjava.ome.UnifiedSinglescaleNode; |
| 9 | +import dev.zarr.zarrjava.ome.Well; |
7 | 10 | import dev.zarr.zarrjava.ome.metadata.Axis; |
8 | 11 | import dev.zarr.zarrjava.ome.metadata.CoordinateTransformation; |
9 | 12 | 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; |
10 | 19 | import dev.zarr.zarrjava.store.FilesystemStore; |
11 | 20 | import dev.zarr.zarrjava.store.StoreHandle; |
12 | 21 | import dev.zarr.zarrjava.v3.Array; |
|
15 | 24 |
|
16 | 25 | import java.util.Arrays; |
17 | 26 | import java.util.Collections; |
| 27 | +import java.util.HashMap; |
18 | 28 | import java.util.List; |
| 29 | +import java.util.Map; |
19 | 30 |
|
20 | 31 | import static org.junit.jupiter.api.Assertions.*; |
21 | 32 |
|
@@ -202,4 +213,270 @@ void readV04_entryHasVersion() throws Exception { |
202 | 213 | MultiscalesEntry entry = image.getMultiscalesEntry(0); |
203 | 214 | assertEquals("0.4", entry.version); |
204 | 215 | } |
| 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 | + } |
205 | 482 | } |
0 commit comments