diff --git a/build.gradle b/build.gradle index 78270ef6..02f3a24b 100644 --- a/build.gradle +++ b/build.gradle @@ -40,7 +40,7 @@ dependencies { implementation 'org.apache.tika:tika-core:1.28.5' testImplementation 'info.picocli:picocli:4.7.5' - testImplementation 'com.glencoesoftware:bioformats2raw:0.9.1' + testImplementation 'com.glencoesoftware:bioformats2raw:0.11.0' } test { diff --git a/src/test/java/com/glencoesoftware/omero/zarr/TestZarr.java b/src/test/java/com/glencoesoftware/omero/zarr/TestZarr.java deleted file mode 100644 index 952ef294..00000000 --- a/src/test/java/com/glencoesoftware/omero/zarr/TestZarr.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (C) 2025 University of Dundee & Open Microscopy Environment. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -package com.glencoesoftware.omero.zarr; - -import com.bc.zarr.ArrayParams; -import com.bc.zarr.DataType; -import com.bc.zarr.DimensionSeparator; -import com.bc.zarr.ZarrArray; -import com.bc.zarr.ZarrGroup; -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferByte; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.OptionalInt; -import java.util.Random; -import ucar.ma2.InvalidRangeException; - -/** - * TestZarr is a utility class for creating and populating a Zarr with different number and - * order of dimensions. - */ -public class TestZarr { - - private int sizeX = 512; - private int sizeY = 256; - private int sizeZ = 5; - private int sizeT = 10; - private int sizeC = 3; - private String order = "TCZYX"; // Note: Reverse of ome.model.enums.DimensionOrder - private Path path = Path.of("./test.zarr"); - private DataType dataType = DataType.u1; - private boolean overwrite = false; - - // Text which is displayed on each plane - private String text = "Channel %s, Timepoint %s, Z-plane %s"; - // If not specified then the position will be random - private OptionalInt textX = OptionalInt.empty(); - private OptionalInt textY = OptionalInt.empty(); - - private ZarrArray array; - - /** - * Create a new TestZarr object with default values. - */ - public TestZarr() throws IOException { - } - - /** - * Create a new TestZarr object with custom values. - */ - public TestZarr(int sizeX, int sizeY, int sizeZ, int sizeT, int sizeC, - String order, String path, DataType dataType, boolean overwrite) - throws IOException { - this.sizeX = sizeX; - this.sizeY = sizeY; - this.sizeZ = sizeZ; - this.sizeT = sizeT; - this.sizeC = sizeC; - this.order = order; - this.path = Path.of(path); - this.dataType = dataType; - this.overwrite = overwrite; - } - - /** - * Initialize the Zarr array. - */ - public TestZarr init() throws IOException { - if (order == null || order.isEmpty()) { - throw new IllegalArgumentException("Order must specified."); - } - this.order = this.order.toUpperCase(); - if (!order.contains("X") || !order.contains("Y")) { - throw new IllegalArgumentException("Order must contain X and Y"); - } - if (!order.contains("C")) { - this.sizeC = 0; - } - if (!order.contains("Z")) { - this.sizeZ = 0; - } - if (!order.contains("T")) { - this.sizeT = 0; - } - if (sizeC == 0) { - this.order = order.replace("C", ""); - } - if (sizeZ == 0) { - this.order = order.replace("Z", ""); - } - if (sizeT == 0) { - this.order = order.replace("T", ""); - } - int[] shape = new int[order.length()]; - if (order.contains("C")) { - shape[order.indexOf("C")] = sizeC; - } - if (order.contains("T")) { - shape[order.indexOf("T")] = sizeT; - } - if (order.contains("Z")) { - shape[order.indexOf("Z")] = sizeZ; - } - shape[order.indexOf("Y")] = sizeY; - shape[order.indexOf("X")] = sizeX; - - if (Files.exists(path)) { - if (overwrite) { - Files.walk(path) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); - } else { - throw new IOException("Path already exists"); - } - } - - Path seriesPath = path.resolve("0"); // image 0 (one image) - Path imgPath = seriesPath.resolve("0"); // resolution 0 (one resolution) - - // Create parent directories if they don't exist - Files.createDirectories(imgPath.getParent()); - - array = ZarrArray.create(imgPath, new ArrayParams() - .shape(shape) - .dataType(dataType) - .dimensionSeparator(DimensionSeparator.SLASH) - ); - return this; - } - - /** - * Fill the Zarr array with pixel data. - */ - public TestZarr createImage() throws IOException, InvalidRangeException { - for (int c = 0; c < Math.max(1, sizeC); c++) { - for (int t = 0; t < Math.max(1, sizeT); t++) { - for (int z = 0; z < Math.max(1, sizeZ); z++) { - int[] sh = new int[order.length()]; - int[] off = new int[order.length()]; - if (order.contains("C")) { - sh[order.indexOf("C")] = 1; - off[order.indexOf("C")] = c; - } - if (order.contains("T")) { - sh[order.indexOf("T")] = 1; - off[order.indexOf("T")] = t; - } - if (order.contains("Z")) { - sh[order.indexOf("Z")] = 1; - off[order.indexOf("Z")] = z; - } - sh[order.indexOf("Y")] = sizeY; - sh[order.indexOf("X")] = sizeX; - off[order.indexOf("Y")] = 0; - off[order.indexOf("X")] = 0; - byte[] plane = generateGreyscaleImageWithText(c, z, t); - array.write(plane, sh, off); - } - } - } - return this; - } - - /** - * Save the image metadata to the Zarr file. - */ - public TestZarr createMetadata() throws IOException { - List> axes = new ArrayList<>(); - for (int i = 0; i < order.length(); i++) { - Map axisObj = new HashMap<>(); - String axe = Character.toString(order.charAt(i)).toLowerCase(); - axisObj.put("name", axe); - if (axe.equals("c")) { - axisObj.put("type", "channel"); - } else if (axe.equals("t")) { - axisObj.put("type", "time"); - } else if (axe.equals("z")) { - axisObj.put("type", "space"); - } else if (axe.equals("y")) { - axisObj.put("type", "space"); - } else if (axe.equals("x")) { - axisObj.put("type", "space"); - } - axes.add(axisObj); - } - - Map resObj = new HashMap<>(); - resObj.put("path", "0"); - List> transforms = new ArrayList<>(); - Map trans = new HashMap<>(); - trans.put("type", "scale"); - trans.put("scale", new int[] {1, 1, 1, 1, 1}); - transforms.add(trans); - resObj.put("coordinateTransformations", transforms); - List> datasets = new ArrayList<>(); - datasets.add(resObj); - - List msArray = new ArrayList<>(); - Map msData = new HashMap<>(); - msData.put("axes", axes); - msData.put("datasets", datasets); - msArray.add(msData); - Path seriesPath = path.resolve("0"); // image 0 (one image) - - // Create the series directory if it doesn't exist - Files.createDirectories(seriesPath); - - // Create a new ZarrGroup instead of trying to open an existing one - ZarrGroup z = ZarrGroup.create(seriesPath); - Map attrs = new HashMap(); - attrs.put("multiscales", msArray); - z.writeAttributes(attrs); - - return this; - } - - /** - * Generates a grayscale image with text. - * The background is black (0) and the text is white (255). - * - * @return byte array containing the grayscale image data - */ - public byte[] generateGreyscaleImageWithText(int c, int z, int t) { - // Create buffered image - BufferedImage image = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_BYTE_GRAY); - Graphics2D g2d = image.createGraphics(); - - // Set rendering hints for better text quality - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - g2d.setRenderingHint( - RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); - - // Fill background with black - g2d.setColor(Color.BLACK); - g2d.fillRect(0, 0, sizeX, sizeY); - - // Set up text properties - g2d.setColor(Color.WHITE); - int fontSize = Math.min(sizeX, sizeY) / 20; // Scale font size based on image dimensions - g2d.setFont(new Font("Arial", Font.BOLD, fontSize)); - - String planeText = text.format(text, c, t, z); - // Get text dimensions - int textWidth = g2d.getFontMetrics().stringWidth(planeText); - int textHeight = g2d.getFontMetrics().getHeight(); - - // Generate random position for text, ensuring it fits within the image - Random random = new Random(); - int x = textX.isPresent() ? textX.getAsInt() : random.nextInt(sizeX - textWidth); - int y = textY.isPresent() ? textY.getAsInt() - : random.nextInt(sizeY - textHeight) + g2d.getFontMetrics().getAscent(); - - // Draw the text - g2d.drawString(planeText, x, y); - g2d.dispose(); - - // Get the underlying byte array - byte[] imageData = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); - return imageData; - } - - public int getSizeX() { - return sizeX; - } - - /** Set the X dimension size. */ - public TestZarr setSizeX(int sizeX) { - this.sizeX = sizeX; - return this; - } - - public int getSizeY() { - return sizeY; - } - - /** Set the Y dimension size. */ - public TestZarr setSizeY(int sizeY) { - this.sizeY = sizeY; - return this; - } - - public int getSizeZ() { - return sizeZ; - } - - /** Set the Z dimension size. */ - public TestZarr setSizeZ(int sizeZ) { - this.sizeZ = sizeZ; - return this; - } - - public int getSizeT() { - return sizeT; - } - - /** Set the T dimension size. */ - public TestZarr setSizeT(int sizeT) { - this.sizeT = sizeT; - return this; - } - - public int getSizeC() { - return sizeC; - } - - /** Set the C dimension size. */ - public TestZarr setSizeC(int sizeC) { - this.sizeC = sizeC; - return this; - } - - public String getOrder() { - return order; - } - - /** - * Set the order of the dimensions. - * Note: Reverse of ome.model.enums.DimensionOrder, - * e.g. DimensionOrder.XYZCT -> use "TCZYX" - */ - public TestZarr setOrder(String order) { - this.order = order; - return this; - } - - public Path getPath() { - return path; - } - - /** Set the dataset path. */ - public TestZarr setPath(Path path) { - this.path = path; - return this; - } - - public DataType getDataType() { - return dataType; - } - - /** Set the data type. */ - public TestZarr setDataType(DataType dataType) { - this.dataType = dataType; - return this; - } - - public ZarrArray getArray() { - return array; - } - - /** Set whether the dataset can be ovewritten.*/ - public TestZarr setOverwrite(boolean b) { - this.overwrite = b; - return this; - } - - public boolean getOverwrite() { - return overwrite; - } - - public String getText() { - return text; - } - - /** Set the text. */ - public TestZarr setText(String text) { - this.text = text; - return this; - } - - /** Set the X location of the text. */ - public TestZarr setTextX(int textX) { - this.textX = OptionalInt.of(textX); - return this; - } - - /** Set the Y location of the text. */ - public TestZarr setTextY(int textY) { - this.textY = OptionalInt.of(textY); - return this; - } -} diff --git a/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelBufferTest.java b/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelBufferTest.java index b11ddb51..97e408ec 100644 --- a/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelBufferTest.java +++ b/src/test/java/com/glencoesoftware/omero/zarr/ZarrPixelBufferTest.java @@ -189,7 +189,7 @@ public Path writeTestZarr( int sizeY, int sizeX, String pixelType, - int resolutions) throws IOException { + String... options) throws IOException { Path input = fake( "sizeT", Integer.toString(sizeT), @@ -197,46 +197,10 @@ public Path writeTestZarr( "sizeZ", Integer.toString(sizeZ), "sizeY", Integer.toString(sizeY), "sizeX", Integer.toString(sizeX), - "pixelType", pixelType, - "resolutions", Integer.toString(resolutions)); + "pixelType", pixelType); Path output = tmpDir.getRoot().toPath().resolve("output.zarr"); - assertBioFormats2Raw(input, output); - - Map msData = new HashMap<>(); - Map msMetadata = new HashMap<>(); - msMetadata.put("method", "loci.common.image.SimpleImageScaler"); - msMetadata.put("version", "Bio-Formats 6.5.1"); - msData.put("metadata", msMetadata); - msData.put("datasets", getDatasets(resolutions)); - msData.put("version", "0.1"); - List msArray = new ArrayList<>(); - msArray.add(msData); - ZarrGroup z = ZarrGroup.open(output.resolve("0")); - Map attrs = new HashMap(); - attrs.put("multiscales", msArray); - z.writeAttributes(attrs); + assertBioFormats2Raw(input, output, options); return output; - - } - - List> getDatasets(int resolutions) { - List> datasets = new ArrayList<>(); - for (int i = 0; i < resolutions; i++) { - Map resObj = new HashMap<>(); - resObj.put("path", Integer.toString(i)); - datasets.add(resObj); - } - return datasets; - } - - List> getAxes(String order) { - List> axes = new ArrayList<>(); - for (int i = 0; i < order.length(); i++) { - Map axisObj = new HashMap<>(); - axisObj.put("name", Character.toString(order.charAt(i))); - axes.add(axisObj); - } - return axes; } @Test @@ -247,10 +211,10 @@ public void testGetChunks() throws IOException { int sizeY = 512; int sizeX = 2048; int resolutions = 3; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", + "--resolutions", String.valueOf(resolutions)); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { int[][] chunks = zpbuf.getChunks(); @@ -259,10 +223,34 @@ public void testGetChunks() throws IOException { new int[] {1, 1, 1, 256, 1024}, new int[] {1, 1, 1, 128, 512} }; - for (int i = 0; i < chunks.length; i++) { - Assert.assertTrue(Arrays.equals( - chunks[i], expectedChunks[i])); - } + Assert.assertEquals(chunks, expectedChunks); + } + } + + @Test + public void testGet3DChunks() throws IOException { + int sizeT = 1; + int sizeC = 3; + int sizeZ = 16; + int sizeY = 512; + int sizeX = 2048; + int resolutions = 4; + int chunkDepth = 16; + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr( + sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", + "--resolutions", String.valueOf(resolutions), + "--chunk-depth", String.valueOf(chunkDepth)); + try (ZarrPixelBuffer zpbuf = + createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { + int[][] chunks = zpbuf.getChunks(); + int[][] expectedChunks = new int[][] { + new int[] {1, 1, chunkDepth, 512, 1024}, + new int[] {1, 1, chunkDepth, 256, 1024}, + new int[] {1, 1, chunkDepth, 128, 512}, + new int[] {1, 1, chunkDepth, 64, 256} + }; + Assert.assertEquals(chunks, expectedChunks); } } @@ -274,17 +262,26 @@ public void testGetDatasets() throws IOException { int sizeY = 512; int sizeX = 2048; int resolutions = 3; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", - resolutions); + sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", + "--resolutions", String.valueOf(resolutions)); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { + List> datasets = zpbuf.getDatasets(); - List> expectedDatasets = getDatasets(3); + Assert.assertEquals(datasets.size(), resolutions); for (int i = 0; i < datasets.size(); i++) { - Assert.assertEquals(datasets.get(i), expectedDatasets.get(i)); + Assert.assertEquals(datasets.get(i).get("path"), Integer.toString(i)); + List> transformations = + new ArrayList>(); + Map scale = new HashMap(); + scale.put("type", "scale"); + scale.put("scale", Arrays.asList( + new Double[] {1.0, 1.0, 1.0, Math.pow(2, i), Math.pow(2, i)})); + transformations.add(scale); + Assert.assertEquals( + datasets.get(i).get("coordinateTransformations"), transformations); } } } @@ -297,10 +294,10 @@ public void testGetResolutionDescriptions() throws IOException { int sizeY = 512; int sizeX = 2048; int resolutions = 3; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", + "--resolutions", String.valueOf(resolutions)); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { List> expected = new ArrayList>(); @@ -338,17 +335,15 @@ public void testGetTile() throws IOException, InvalidRangeException { int sizeZ = 4; int sizeY = 5; int sizeX = 6; - int resolutions = 1; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "int32", resolutions); + int length = sizeT * sizeC * sizeZ * sizeY * sizeX; + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "int32"); ZarrArray test = ZarrArray.open(output.resolve("0").resolve("0")); - int[] data = new int[2 * 3 * 4 * 5 * 6]; - for (int i = 0; i < 2 * 3 * 4 * 5 * 6; i++) { + int[] data = new int[length]; + for (int i = 0; i < length; i++) { data[i] = i; } - test.write(data, new int[] {2, 3, 4, 5, 6}, new int[] {0, 0, 0, 0, 0}); + test.write(data, new int[] {sizeT, sizeC, sizeZ, sizeY, sizeX}, new int[] {0, 0, 0, 0, 0}); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { PixelData pixelData = zpbuf.getTile(0, 0, 0, 0, 0, 2, 2); @@ -427,6 +422,52 @@ private byte[] getPlane( return asBytes; } + private void assertPixels( + ZarrPixelBuffer zpbuf, int sizeX, int sizeY, int sizeZ, int sizeC, int sizeT) + throws IOException { + + for (int t = 0; t < sizeT; t++) { + for (int c = 0; c < sizeC; c++) { + for (int z = 0; z < sizeZ; z++) { + byte[] plane = zpbuf.getPlane(z, c, t).getData().array(); + int[] seriesPlaneNumberZCT = FakeReader.readSpecialPixels( + plane, zpbuf.getPixelsType(), false); + int planeNumber = FormatTools.getIndex( + DimensionOrder.VALUE_XYZCT, + sizeZ, sizeC, sizeT, sizeZ * sizeC * sizeT, + z, c, t); + Assert.assertArrayEquals( + Arrays.toString(seriesPlaneNumberZCT), + new int[] {0, planeNumber, z, c, t}, + seriesPlaneNumberZCT); + } + } + } + } + + private void assertAxes(ZarrPixelBuffer zpbuf, String order) { + + Map axes = zpbuf.getAxesOrder(); + int indexMax = order.length() - 1; + if (order.contains("T")) { + Assert.assertEquals(indexMax - order.indexOf("T"), axes.get(Axis.T).intValue()); + } else { + Assert.assertFalse(axes.containsKey(Axis.T)); + } + if (order.contains("C")) { + Assert.assertEquals(indexMax - order.indexOf("C"), axes.get(Axis.C).intValue()); + } else { + Assert.assertFalse(axes.containsKey(Axis.C)); + } + if (order.contains("Z")) { + Assert.assertEquals(indexMax - order.indexOf("Z"), axes.get(Axis.Z).intValue()); + } else { + Assert.assertFalse(axes.containsKey(Axis.Z)); + } + Assert.assertEquals(indexMax - order.indexOf("Y"), axes.get(Axis.Y).intValue()); + Assert.assertEquals(indexMax - order.indexOf("X"), axes.get(Axis.X).intValue()); + } + private byte[] getCol(byte[] plane, int x, int sizeX, int sizeY) { // XXX: Is not data type agnostic, expects signed 32-bit integer pixels int bytesPerPixel = 4; @@ -448,11 +489,8 @@ public void testGetTimepointStackPlaneRowCol() int sizeZ = 4; int sizeY = 1024; int sizeX = 2048; - int resolutions = 1; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "int32", resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "int32"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 2048, 2048)) { for (int t = 0; t < sizeT; t++) { @@ -509,18 +547,15 @@ public void testGetTileLargerThanImage() int sizeZ = 4; int sizeY = 5; int sizeX = 6; - int resolutions = 1; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "int32", - resolutions); + int length = sizeT * sizeC * sizeZ * sizeY * sizeX; + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "int32"); ZarrArray test = ZarrArray.open(output.resolve("0").resolve("0")); - int[] data = new int[2 * 3 * 4 * 5 * 6]; - for (int i = 0; i < 2 * 3 * 4 * 5 * 6; i++) { + int[] data = new int[length]; + for (int i = 0; i < length; i++) { data[i] = i; } - test.write(data, new int[] {2, 3, 4, 5, 6}, new int[] {0, 0, 0, 0, 0}); + test.write(data, new int[] {sizeT, sizeC, sizeZ, sizeY, sizeX}, new int[] {0, 0, 0, 0, 0}); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { zpbuf.setResolutionLevel(0); @@ -543,12 +578,8 @@ public void testTileIntegerOverflow() int sizeZ = 1; int sizeY = 1; int sizeX = 1; - int resolutions = 1; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", - resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16"); // Hack the .zarray so we can appear as though we have more data than // we actually have written above. @@ -573,12 +604,8 @@ public void testTileExceedsMinMax() throws IOException { int sizeZ = 1; int sizeY = 512; int sizeX = 2048; - int resolutions = 3; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", - resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 32, 32)) { @@ -595,11 +622,8 @@ public void testCheckBoundsValidZeros() throws IOException { int sizeZ = 3; int sizeY = 512; int sizeX = 2048; - int resolutions = 3; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { zpbuf.checkBounds(0, 0, 0, 0, 0); @@ -613,11 +637,8 @@ public void testCheckBoundsValidEnd() throws IOException { int sizeZ = 3; int sizeY = 512; int sizeX = 2048; - int resolutions = 3; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { zpbuf.checkBounds(2047, 511, 2, 1, 0); @@ -631,11 +652,8 @@ public void testCheckBoundsOutOfRange() throws IOException { int sizeZ = 3; int sizeY = 512; int sizeX = 2048; - int resolutions = 3; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { zpbuf.checkBounds(2048, 511, 2, 1, 0); @@ -649,11 +667,9 @@ public void testCheckBounds() throws IOException { int sizeZ = 3; int sizeY = 512; int sizeX = 2048; - int resolutions = 3; Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { zpbuf.checkBounds(-1, 0, 0, 0, 0); @@ -667,11 +683,8 @@ public void testGetTileSize() throws IOException { int sizeZ = 1; int sizeY = 2048; int sizeX = 2048; - int resolutions = 3; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { Dimension tileSize = zpbuf.getTileSize(); @@ -689,10 +702,8 @@ public void testUint16() throws IOException { int sizeX = 2048; int resolutions = 3; int bytesPerPixel = 2; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { Assert.assertEquals(FormatTools.UINT16, zpbuf.getPixelsType()); @@ -711,10 +722,8 @@ public void testFloat() throws IOException { int sizeX = 2048; int resolutions = 3; int bytesPerPixel = 4; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "float", resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "float"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { Assert.assertEquals(FormatTools.FLOAT, zpbuf.getPixelsType()); @@ -731,12 +740,9 @@ public void testSizes() throws IOException { int sizeZ = 3; int sizeY = 1024; int sizeX = 2048; - int resolutions = 3; int bytesPerPixel = 2; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { // Plane size @@ -774,13 +780,13 @@ public void testSetResolutionLevelOutOfBounds() throws IOException { int sizeY = 2048; int sizeX = 2048; int resolutions = 3; - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", resolutions); + sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", + "--resolutions", String.valueOf(resolutions)); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), 1024, 1024)) { - zpbuf.setResolutionLevel(3); + zpbuf.setResolutionLevel(resolutions); } } @@ -792,11 +798,10 @@ public void testDownsampledZ() throws IOException { int sizeY = 2048; int sizeX = 2048; int resolutions = 3; - - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint8", resolutions); + sizeT, sizeC, sizeZ, sizeY, sizeX, "uint8", + "--resolutions", String.valueOf(resolutions)); // Hack the .zarray to hide Z sections in lower resolutions for (int r = 1; r < resolutions; r++) { @@ -833,22 +838,9 @@ public void testReadDataNonDefaultAxes() String order = DimensionOrder.VALUE_XYCTZ; // Default XYZCT String revOrder = new StringBuilder(order).reverse().toString(); Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", new DimensionOrder(order)); - - Path output = tmpDir.getRoot().toPath().resolve("test.zarr"); - new TestZarr() - .setPath(output) - .setOverwrite(true) - .setSizeX(sizeX) - .setSizeY(sizeY) - .setSizeZ(sizeZ) - .setSizeT(sizeT) - .setSizeC(sizeC) - .setOrder(revOrder) - .setDataType(com.bc.zarr.DataType.i4) // getStack expects int32 - .init() - .createImage() - .createMetadata(); + null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", new DimensionOrder(order)); + Path output = writeTestZarr( + sizeT, sizeC, sizeZ, sizeY, sizeX, "int32", "--dimension-order", order); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), sizeX, sizeY)) { @@ -897,67 +889,58 @@ public void testDefaultOrder() int sizeZ = 16; int sizeY = 256; int sizeX = 512; - int resolutions = 1; - - Pixels pixels = new Pixels( - null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); - Path output = writeTestZarr( - sizeT, sizeC, sizeZ, sizeY, sizeX, "uint8", resolutions); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint8"); try (ZarrPixelBuffer zpbuf = createPixelBuffer(pixels, output.resolve("0"), sizeX, sizeY)) { - Map axes = zpbuf.getAxesOrder(); - Assert.assertEquals(0, axes.get(Axis.T).intValue()); - Assert.assertEquals(1, axes.get(Axis.C).intValue()); - Assert.assertEquals(2, axes.get(Axis.Z).intValue()); - Assert.assertEquals(3, axes.get(Axis.Y).intValue()); - Assert.assertEquals(4, axes.get(Axis.X).intValue()); Assert.assertEquals(sizeT, zpbuf.getSizeT()); Assert.assertEquals(sizeC, zpbuf.getSizeC()); Assert.assertEquals(sizeZ, zpbuf.getSizeZ()); Assert.assertEquals(sizeY, zpbuf.getSizeY()); Assert.assertEquals(sizeX, zpbuf.getSizeX()); + assertAxes(zpbuf, "XYZCT"); } } @Test - public void testXYCTZ() throws IOException, InvalidRangeException { - testDimensions(512, 1024, 2, 3, 4); + public void testXYZCT() throws IOException, InvalidRangeException { + testCompactDimensions(512, 1024, 2, 3, 4, "XYZCT"); } @Test public void testXYCT() throws IOException, InvalidRangeException { - testDimensions(512, 1024, 0, 3, 4); + testCompactDimensions(512, 1024, 1, 3, 4, "XYCT"); } @Test - public void testXYCZ() throws IOException, InvalidRangeException { - testDimensions(512, 1024, 2, 3, 0); + public void testXYZC() throws IOException, InvalidRangeException { + testCompactDimensions(512, 1024, 2, 3, 1, "XYZC"); } @Test - public void testXYTZ() throws IOException, InvalidRangeException { - testDimensions(512, 1024, 2, 0, 4); + public void testXYZT() throws IOException, InvalidRangeException { + testCompactDimensions(512, 1024, 2, 1, 4, "XYZT"); } @Test public void testXYZ() throws IOException, InvalidRangeException { - testDimensions(512, 1024, 2, 0, 0); + testCompactDimensions(512, 1024, 2, 1, 1, "XYZ"); } @Test public void testXYT() throws IOException, InvalidRangeException { - testDimensions(512, 1024, 0, 0, 4); + testCompactDimensions(512, 1024, 1, 1, 4, "XYT"); } @Test public void testXYC() throws IOException, InvalidRangeException { - testDimensions(512, 1024, 0, 3, 0); + testCompactDimensions(512, 1024, 1, 3, 1, "XYC"); } @Test public void testXY() throws IOException, InvalidRangeException { - testDimensions(512, 1024, 0, 0, 0); + testCompactDimensions(512, 1024, 1, 1, 1, "XY"); } @Test @@ -991,89 +974,38 @@ public void testOrderXYZTC() throws IOException, InvalidRangeException { } private void testOrder(String order) throws IOException, InvalidRangeException { - Path testZarrPath = tmpDir.getRoot().toPath().resolve("test.zarr"); - TestZarr testZarr = new TestZarr() - .setPath(testZarrPath) - .setOrder(new StringBuilder(order).reverse().toString()) - .init() - .createImage() - .createMetadata(); - + int sizeT = 2; + int sizeC = 3; + int sizeZ = 4; + int sizeY = 256; + int sizeX = 512; Pixels pixels = new Pixels( - null, null, testZarr.getSizeX(), testZarr.getSizeY(), testZarr.getSizeZ(), - testZarr.getSizeC(), testZarr.getSizeT(), "", new DimensionOrder(order)); - - try (ZarrPixelBuffer zpbuf = createPixelBuffer( - pixels, testZarrPath.resolve("0"), testZarr.getSizeX(), testZarr.getSizeY())) { - Map axes = zpbuf.getAxesOrder(); - Assert.assertEquals(4 - order.indexOf("Z"), axes.get(Axis.Z).intValue()); - Assert.assertEquals(4 - order.indexOf("T"), axes.get(Axis.T).intValue()); - Assert.assertEquals(4 - order.indexOf("C"), axes.get(Axis.C).intValue()); - Assert.assertEquals(4 - order.indexOf("Y"), axes.get(Axis.Y).intValue()); - Assert.assertEquals(4 - order.indexOf("X"), axes.get(Axis.X).intValue()); - Assert.assertEquals(testZarr.getSizeT(), zpbuf.getSizeT()); - Assert.assertEquals(testZarr.getSizeC(), zpbuf.getSizeC()); - Assert.assertEquals(testZarr.getSizeZ(), zpbuf.getSizeZ()); - Assert.assertEquals(testZarr.getSizeY(), zpbuf.getSizeY()); - Assert.assertEquals(testZarr.getSizeX(), zpbuf.getSizeX()); + null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", new DimensionOrder(order)); + Path output = writeTestZarr( + sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", "--dimension-order", order); + + try (ZarrPixelBuffer zpbuf = + createPixelBuffer(pixels, output.resolve("0"), sizeX, sizeY)) { + Assert.assertEquals(sizeT, zpbuf.getSizeT()); + Assert.assertEquals(sizeC, zpbuf.getSizeC()); + Assert.assertEquals(sizeZ, zpbuf.getSizeZ()); + Assert.assertEquals(sizeY, zpbuf.getSizeY()); + Assert.assertEquals(sizeX, zpbuf.getSizeX()); + assertAxes(zpbuf, order); + assertPixels(zpbuf, sizeX, sizeY, sizeZ, sizeC, sizeT); } } - private void testDimensions(int sizeX, int sizeY, int sizeZ, int sizeC, int sizeT) + private void testCompactDimensions( + int sizeX, int sizeY, int sizeZ, int sizeC, int sizeT, String order) throws IOException, InvalidRangeException { - String order = DimensionOrder.VALUE_XYZCT; - if (sizeT == 0) { - order.replace("T", ""); - } - if (sizeZ == 0) { - order.replace("Z", ""); - } - if (sizeC == 0) { - order.replace("C", ""); + Pixels pixels = new Pixels(null, null, sizeX, sizeY, sizeZ, sizeC, sizeT, "", null); + Path output = writeTestZarr(sizeT, sizeC, sizeZ, sizeY, sizeX, "uint16", "--compact"); + try (ZarrPixelBuffer zpbuf = + createPixelBuffer(pixels, output.resolve("0"), sizeX, sizeY)) { + assertAxes(zpbuf, order); + assertPixels(zpbuf, sizeX, sizeY, sizeZ, sizeC, sizeT); } - - int textX = 10; - int textY = 10; - Path testZarrPath = tmpDir.getRoot().toPath().resolve("test.zarr"); - TestZarr testZarr = new TestZarr() - .setPath(testZarrPath) - .setOverwrite(true) - .setSizeX(sizeX) - .setSizeY(sizeY) - .setSizeZ(sizeZ) - .setSizeT(sizeT) - .setSizeC(sizeC) - .setOrder(new StringBuilder(order).reverse().toString()) - .setTextX(textX) - .setTextY(textY) - .init() - .createImage() - .createMetadata(); - - int pixZ = sizeZ > 0 ? sizeZ : 1; - int pixC = sizeC > 0 ? sizeC : 1; - int pixT = sizeT > 0 ? sizeT : 1; - - Pixels pixels = new Pixels( - null, new PixelsType(PixelsType.VALUE_INT32), - sizeX, sizeY, pixZ, pixC, pixT, "", new DimensionOrder(DimensionOrder.VALUE_XYZCT)); - - int expectedTests = pixC * pixT * pixZ; - int testCount = 0; - try (ZarrPixelBuffer zpbuf = createPixelBuffer( - pixels, testZarrPath.resolve("0"), sizeX, sizeY)) { - for (int t = 0; t < Math.max(sizeT, 1); t++) { - for (int z = 0; z < Math.max(sizeZ, 1); z++) { - for (int c = 0; c < Math.max(sizeC, 1); c++) { - byte[] expected = testZarr.generateGreyscaleImageWithText(c, z, t); - byte[] actual = zpbuf.getPlane(z, c, t).getData().array(); - Assert.assertArrayEquals(expected, actual); - testCount++; - } - } - } - } - Assert.assertEquals(expectedTests, testCount); } }