diff --git a/src/main/java/cz/it4i/qcmp/io/CallbackInputData.java b/src/main/java/cz/it4i/qcmp/io/CallbackInputData.java new file mode 100644 index 0000000000000000000000000000000000000000..ef046c29022f0cd371344c1cd9f01ddd370e1e16 --- /dev/null +++ b/src/main/java/cz/it4i/qcmp/io/CallbackInputData.java @@ -0,0 +1,43 @@ +package cz.it4i.qcmp.io; + +import cz.it4i.qcmp.data.V3i; + +public class CallbackInputData extends InputData { + + private final String cacheHint; + private final LoadCallback pixelLoadCallback; + + /** + * Interface defining method for pixel data loading. + */ + public interface LoadCallback { + /** + * Callback to load pixel value at specified position. + * + * @param x X position. + * @param y Y position. + * @param z Z position. + * @return Pixel value at specified position. + */ + int getValueAt(final int x, final int y, final int z); + } + + public CallbackInputData(final LoadCallback pixelLoadCallback, + final V3i dimensions, + final String cacheHint) { + this.pixelLoadCallback = pixelLoadCallback; + this.cacheHint = cacheHint; + setDataLoaderType(DataLoaderType.CallbackLoader); + setPixelType(PixelType.Gray16); + setDimension(dimensions); + } + + @Override + public String getCacheFileName() { + return cacheHint; + } + + public final LoadCallback getPixelLoadCallback() { + return pixelLoadCallback; + } +} diff --git a/src/main/java/cz/it4i/qcmp/io/InputData.java b/src/main/java/cz/it4i/qcmp/io/InputData.java index d6a3fe37d338a1b8587a7ed3966c6b02bb5476ce..0cda8309055e301d3aa15236a757a811d9227c5e 100644 --- a/src/main/java/cz/it4i/qcmp/io/InputData.java +++ b/src/main/java/cz/it4i/qcmp/io/InputData.java @@ -11,7 +11,8 @@ public abstract class InputData { RawDataLoader, SCIFIOLoader, ImageJBufferLoader, - FlatBufferLoader + FlatBufferLoader, + CallbackLoader } public enum PixelType { diff --git a/src/main/java/cz/it4i/qcmp/io/loader/CallbackLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/CallbackLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..629ac238110453a8e7aacbf0ff7f34432fa3df1f --- /dev/null +++ b/src/main/java/cz/it4i/qcmp/io/loader/CallbackLoader.java @@ -0,0 +1,105 @@ +package cz.it4i.qcmp.io.loader; + +import cz.it4i.qcmp.data.Range; +import cz.it4i.qcmp.data.V2i; +import cz.it4i.qcmp.data.V3i; +import cz.it4i.qcmp.io.CallbackInputData; + +import java.io.IOException; +import java.util.Arrays; + +public class CallbackLoader extends BasicLoader implements IPlaneLoader { + + private final CallbackInputData callbackInputData; + private final CallbackInputData.LoadCallback pixelLoad; + + public CallbackLoader(final CallbackInputData callbackInputData) { + super(callbackInputData.getDimensions()); + this.callbackInputData = callbackInputData; + this.pixelLoad = callbackInputData.getPixelLoadCallback(); + } + + @Override + protected int valueAt(final int plane, final int x, final int y, final int width) { + return pixelLoad.getValueAt(x, y, plane); + } + + + @Override + public int[] loadPlaneData(final int plane) { + final int planePixelCount = dims.getX() * dims.getY(); + final int[] planeData = new int[planePixelCount]; + + int index = 0; + for (int y = 0; y < dims.getY(); y++) { + for (int x = 0; x < dims.getX(); x++) { + planeData[index++] = pixelLoad.getValueAt(x, y, plane); + } + } + return planeData; + } + + @Override + public int[] loadPlanesU16Data(final int[] planes) throws IOException { + if (planes.length < 1) { + return new int[0]; + } else if (planes.length == 1) { + return loadPlaneData(planes[0]); + } else if (planes.length == dims.getZ()) { + return loadAllPlanesU16Data(); + } + final int planePixelCount = dims.getX() * dims.getY(); + final long totalValueCount = (long) planePixelCount * (long) planes.length; + if (totalValueCount > (long) Integer.MAX_VALUE) { + throw new IOException("Unable to load image data for planes, file size is too big."); + } + + Arrays.sort(planes); + + final int[] destBuffer = new int[(int) totalValueCount]; + int index = 0; + for (final int plane : planes) { + for (int y = 0; y < dims.getY(); y++) { + for (int x = 0; x < dims.getX(); x++) { + destBuffer[index++] = pixelLoad.getValueAt(x, y, plane); + } + } + } + return destBuffer; + } + + @Override + public int[] loadAllPlanesU16Data() throws IOException { + final long totalValueCount = dims.multiplyTogether(); + if (totalValueCount > (long) Integer.MAX_VALUE) { + throw new IOException("Unable to load all image data, file size is too big."); + } + + final int[] destBuffer = new int[(int) totalValueCount]; + int index = 0; + for (int z = 0; z < dims.getZ(); z++) { + for (int y = 0; y < dims.getY(); y++) { + for (int x = 0; x < dims.getX(); x++) { + destBuffer[index++] = pixelLoad.getValueAt(x, y, z); + } + } + } + + return destBuffer; + } + + @Override + public int[][] loadRowVectors(final int vectorSize, final Range<Integer> planeRange) { + return loadRowVectorsImplByValueAt(vectorSize, planeRange); + } + + @Override + public int[][] loadBlocks(final V2i blockDim, final Range<Integer> planeRange) { + return loadBlocksImplByValueAt(blockDim, planeRange); + } + + @Override + public int[][] loadVoxels(final V3i voxelDim, final Range<Integer> planeRange) { + return loadVoxelsImplByValueAt(voxelDim, planeRange); + } +} diff --git a/src/main/java/cz/it4i/qcmp/io/loader/PlaneLoaderFactory.java b/src/main/java/cz/it4i/qcmp/io/loader/PlaneLoaderFactory.java index e35ff329969de533a8b22e82f2660cd29ffc3bf2..ce597f26883727e3c6f60b20241a284a82acd6c3 100644 --- a/src/main/java/cz/it4i/qcmp/io/loader/PlaneLoaderFactory.java +++ b/src/main/java/cz/it4i/qcmp/io/loader/PlaneLoaderFactory.java @@ -1,9 +1,6 @@ package cz.it4i.qcmp.io.loader; -import cz.it4i.qcmp.io.BufferInputData; -import cz.it4i.qcmp.io.FileInputData; -import cz.it4i.qcmp.io.FlatBufferInputData; -import cz.it4i.qcmp.io.InputData; +import cz.it4i.qcmp.io.*; public final class PlaneLoaderFactory { @@ -24,6 +21,8 @@ public final class PlaneLoaderFactory { return new ImageJBufferLoader((BufferInputData) inputDataInfo); case FlatBufferLoader: return new FlatBufferLoader((FlatBufferInputData) inputDataInfo); + case CallbackLoader: + return new CallbackLoader((CallbackInputData) inputDataInfo); default: throw new Exception("Unsupported data loader."); }