From 1cd3087b3518e76e36fc8630cdc30828e967a282 Mon Sep 17 00:00:00 2001 From: Vojtech Moravec <vojtech.moravec.st@vsb.cz> Date: Tue, 11 Aug 2020 15:00:14 +0200 Subject: [PATCH] Add new loader type, FlatBufferLoader. This loader is quite similiar to ImageJBufferLoader, except that different plane data are stored in a single flat array. To handle this situation with different loader help us prevent future IndexOutOfBounds exceptions. --- .../azgracompress/io/FlatBufferInputData.java | 52 +++++++++ .../io/loader/FlatBufferLoader.java | 110 ++++++++++++++++++ .../io/loader/PlaneLoaderFactory.java | 3 + 3 files changed, 165 insertions(+) create mode 100644 src/main/java/azgracompress/io/FlatBufferInputData.java create mode 100644 src/main/java/azgracompress/io/loader/FlatBufferLoader.java diff --git a/src/main/java/azgracompress/io/FlatBufferInputData.java b/src/main/java/azgracompress/io/FlatBufferInputData.java new file mode 100644 index 0000000..b6eef34 --- /dev/null +++ b/src/main/java/azgracompress/io/FlatBufferInputData.java @@ -0,0 +1,52 @@ +package azgracompress.io; + +import azgracompress.data.V3i; + +/** + * Input data backed by the single buffer object. + * In this buffer all the dataset pixels are stored. + */ +public class FlatBufferInputData extends InputData { + /** + * Reference to the buffer. + */ + private final Object imageBuffer; + + /** + * Name of the image used in caching. + */ + private final String cacheHint; + + /** + * Create input data backed by buffer object. + * + * @param imageBuffer Image buffer reference. + * @param imageDimensions Image dimensions. + * @param pixelType Image pixel type. + * @param cacheHint Name of the image used in caching. + */ + public FlatBufferInputData(final Object imageBuffer, + final V3i imageDimensions, + final PixelType pixelType, + final String cacheHint) { + this.imageBuffer = imageBuffer; + setDataLoaderType(DataLoaderType.ImageJBufferLoader); + setDimension(imageDimensions); + setPixelType(pixelType); + this.cacheHint = cacheHint; + } + + /** + * Get buffer with the image plane data. + * + * @return Pointer to pixel buffer. + */ + public Object getPixelBuffer() { + return imageBuffer; + } + + @Override + public String getCacheFileName() { + return cacheHint; + } +} diff --git a/src/main/java/azgracompress/io/loader/FlatBufferLoader.java b/src/main/java/azgracompress/io/loader/FlatBufferLoader.java new file mode 100644 index 0000000..81e5d6c --- /dev/null +++ b/src/main/java/azgracompress/io/loader/FlatBufferLoader.java @@ -0,0 +1,110 @@ +package azgracompress.io.loader; + +import azgracompress.data.Range; +import azgracompress.data.V2i; +import azgracompress.data.V3i; +import azgracompress.io.FlatBufferInputData; +import azgracompress.utilities.TypeConverter; + +import java.io.IOException; +import java.util.Arrays; + +/** + * This loader is used when the entire dataset is stored in single buffer (array). + */ +public class FlatBufferLoader extends BasicLoader implements IPlaneLoader { + /** + * Flat buffer information. + */ + private final FlatBufferInputData bufferInputData; + + /** + * Pixel count in single plane. + */ + private final int planePixelCount; + + public FlatBufferLoader(final FlatBufferInputData bufferDataInfo) { + super(bufferDataInfo.getDimensions()); + this.bufferInputData = bufferDataInfo; + planePixelCount = dims.getX() * dims.getY(); + } + + @Override + public boolean supportParallelLoading() { + return true; + } + + private void copyShortArrayIntoBuffer(short[] srcArray, + final int srcOffset, + int[] destBuffer, + final int destOffset, + final int copyLen) { + for (int i = 0; i < copyLen; i++) { + destBuffer[destOffset + i] = TypeConverter.shortToInt(srcArray[srcOffset + i]); + } + } + + @Override + protected int valueAt(final int plane, final int offset) { + return TypeConverter.shortToInt(((short[]) bufferInputData.getPixelBuffer())[(plane * planePixelCount) + offset]); + } + + @Override + public int[] loadPlaneData(final int plane) throws IOException { + final short[] flatBuffer = ((short[]) bufferInputData.getPixelBuffer()); + final int offset = plane * planePixelCount; + final int[] planeData = new int[planePixelCount]; + for (int i = 0; i < planePixelCount; i++) { + planeData[i] = TypeConverter.shortToInt(flatBuffer[offset + i]); + } + 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 == bufferInputData.getDimensions().getZ()) { // Maybe? + return loadAllPlanesU16Data(); + } + 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 short[] flatBuffer = (short[]) bufferInputData.getPixelBuffer(); + int[] destBuffer = new int[(int) totalValueCount]; + int destOffset = 0; + for (final int planeIndex : planes) { + final int planeOffset = planeIndex * planePixelCount; + copyShortArrayIntoBuffer(flatBuffer, planeOffset, destBuffer, destOffset, planePixelCount); + destOffset += planePixelCount; + } + return destBuffer; + } + + @Override + public int[] loadAllPlanesU16Data() { + final short[] flatBuffer = (short[]) bufferInputData.getPixelBuffer(); + return TypeConverter.shortArrayToIntArray(flatBuffer); + } + + @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) throws IOException { + return loadVoxelsImplByValueAt(voxelDim, planeRange); + } +} diff --git a/src/main/java/azgracompress/io/loader/PlaneLoaderFactory.java b/src/main/java/azgracompress/io/loader/PlaneLoaderFactory.java index 6783ba6..b34f67e 100644 --- a/src/main/java/azgracompress/io/loader/PlaneLoaderFactory.java +++ b/src/main/java/azgracompress/io/loader/PlaneLoaderFactory.java @@ -2,6 +2,7 @@ package azgracompress.io.loader; import azgracompress.io.BufferInputData; import azgracompress.io.FileInputData; +import azgracompress.io.FlatBufferInputData; import azgracompress.io.InputData; public final class PlaneLoaderFactory { @@ -21,6 +22,8 @@ public final class PlaneLoaderFactory { return new SCIFIOLoader((FileInputData) inputDataInfo); case ImageJBufferLoader: return new ImageJBufferLoader((BufferInputData) inputDataInfo); + case FlatBufferLoader: + return new FlatBufferLoader((FlatBufferInputData) inputDataInfo); default: throw new Exception("Unsupported data loader."); } -- GitLab