diff --git a/settings.gradle.kts b/settings.gradle.kts index df2a39d..91cbc22 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,7 +10,7 @@ pluginManagement { rootProject.name = "qupath-imglib2" // Used for version catalogs (including Java compatibility) -val qupathVersion = "0.6.0" +val qupathVersion = "0.7.0" val sciJavaVersion = "43.0.0" dependencyResolutionManagement { diff --git a/src/main/java/qupath/ext/imglib2/accesses/AccessTools.java b/src/main/java/qupath/ext/imglib2/accesses/AccessTools.java index fd37643..5a0d631 100644 --- a/src/main/java/qupath/ext/imglib2/accesses/AccessTools.java +++ b/src/main/java/qupath/ext/imglib2/accesses/AccessTools.java @@ -45,19 +45,16 @@ public static boolean isSampleModelDirectlyUsable(Raster raster) { * @return the size of the provided data buffer in bytes */ public static int getSizeOfDataBufferInBytes(DataBuffer dataBuffer) { - int bytesPerPixel; - if (dataBuffer instanceof DataBufferByte) { - bytesPerPixel = 1; - } else if (dataBuffer instanceof DataBufferShort || dataBuffer instanceof DataBufferUShort) { - bytesPerPixel = 2; - } else if (dataBuffer instanceof DataBufferInt || dataBuffer instanceof DataBufferFloat) { - bytesPerPixel = 4; - } else if (dataBuffer instanceof DataBufferDouble) { - bytesPerPixel = 8; - } else { - logger.warn("Unexpected data buffer {}. Considering each element of it takes 1 byte", dataBuffer); - bytesPerPixel = 1; - } + int bytesPerPixel = switch (dataBuffer) { + case DataBufferByte _ -> 1; + case DataBufferShort _, DataBufferUShort _ -> 2; + case DataBufferInt _, DataBufferFloat _ -> 4; + case DataBufferDouble _ -> 8; + default -> { + logger.warn("Unexpected data buffer {}. Considering each element of it takes 1 byte", dataBuffer); + yield 1; + } + }; return bytesPerPixel * dataBuffer.getSize() * dataBuffer.getNumBanks(); } diff --git a/src/main/java/qupath/ext/imglib2/accesses/ArgbBufferedImageAccess.java b/src/main/java/qupath/ext/imglib2/accesses/ArgbBufferedImageAccess.java index 6c359ea..8dd1223 100644 --- a/src/main/java/qupath/ext/imglib2/accesses/ArgbBufferedImageAccess.java +++ b/src/main/java/qupath/ext/imglib2/accesses/ArgbBufferedImageAccess.java @@ -1,6 +1,6 @@ package qupath.ext.imglib2.accesses; -import net.imglib2.img.basictypeaccess.IntAccess; +import net.imglib2.img.basictypeaccess.array.IntArray; import net.imglib2.img.basictypeaccess.volatiles.VolatileAccess; import qupath.ext.imglib2.SizableDataAccess; import qupath.lib.common.ColorTools; @@ -8,27 +8,22 @@ import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.awt.image.DataBufferInt; +import java.awt.image.Raster; import java.awt.image.SinglePixelPackedSampleModel; /** - * An {@link IntAccess} whose elements are computed from an (A)RGB {@link BufferedImage}. + * An {@link IntArray} whose elements are computed from an (A)RGB {@link BufferedImage}. *
* If the alpha component is not provided (e.g. if the {@link BufferedImage} has the {@link BufferedImage#TYPE_INT_RGB} type), * then the alpha component of each pixel is considered to be 255. *
- * This {@link IntAccess} is immutable; any attempt to changes its values will result in a + * This {@link IntArray} is immutable; any attempt to changes its values will result in a * {@link UnsupportedOperationException}. *
* This data access is marked as volatile but always contain valid data.
*/
-public class ArgbBufferedImageAccess implements IntAccess, SizableDataAccess, VolatileAccess {
+public class ArgbBufferedImageAccess extends IntArray implements SizableDataAccess, VolatileAccess {
- private final BufferedImage image;
- private final DataBuffer dataBuffer;
- private final int width;
- private final int planeSize;
- private final boolean canUseDataBuffer;
- private final boolean alphaProvided;
private final int size;
/**
@@ -38,39 +33,45 @@ public class ArgbBufferedImageAccess implements IntAccess, SizableDataAccess, Vo
* @throws NullPointerException if the provided image is null
*/
public ArgbBufferedImageAccess(BufferedImage image) {
- this.image = image;
- this.dataBuffer = this.image.getRaster().getDataBuffer();
+ super(createArrayFromImage(image));
- this.width = this.image.getWidth();
- this.planeSize = width * this.image.getHeight();
-
- this.canUseDataBuffer = image.getRaster().getDataBuffer() instanceof DataBufferInt &&
- image.getRaster().getSampleModel() instanceof SinglePixelPackedSampleModel;
- this.alphaProvided = image.getType() == BufferedImage.TYPE_INT_ARGB;
-
- this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
+ this.size = AccessTools.getSizeOfDataBufferInBytes(image.getRaster().getDataBuffer());
}
- @Override
- public int getValue(int index) {
- int xyIndex = index % planeSize;
+ private static int[] createArrayFromImage(BufferedImage image) {
+ Raster raster = image.getRaster();
+ int width = raster.getWidth();
+ int height = raster.getHeight();
+ int planeSize = width * height;
- if (canUseDataBuffer) {
- int pixel = dataBuffer.getElem(0, xyIndex);
+ int[] array = new int[planeSize];
+ if (raster.getSampleModel() instanceof SinglePixelPackedSampleModel && raster.getDataBuffer() instanceof DataBufferInt) {
+ DataBuffer dataBuffer = raster.getDataBuffer();
+ boolean alphaProvided = image.getType() == BufferedImage.TYPE_INT_ARGB;
- if (alphaProvided) {
- return pixel;
- } else {
- return ColorTools.packARGB(
- 255,
- ColorTools.red(pixel),
- ColorTools.green(pixel),
- ColorTools.blue(pixel)
- );
+ for (int i=0; i
- * This {@link ByteAccess} is immutable; any attempt to changes its values will result in a
+ * This {@link ByteArray} is immutable; any attempt to changes its values will result in a
* {@link UnsupportedOperationException}.
*
* This data access is marked as volatile but always contain valid data.
*/
-public class ByteBufferedImageAccess implements ByteAccess, SizableDataAccess, VolatileAccess {
+public class ByteBufferedImageAccess extends ByteArray implements SizableDataAccess, VolatileAccess {
- private final BufferedImage image;
- private final DataBuffer dataBuffer;
- private final int width;
- private final int planeSize;
- private final boolean canUseDataBuffer;
private final int size;
/**
@@ -36,33 +32,9 @@ public class ByteBufferedImageAccess implements ByteAccess, SizableDataAccess, V
* @throws NullPointerException if the provided image is null
*/
public ByteBufferedImageAccess(BufferedImage image) {
- this.image = image;
- this.dataBuffer = this.image.getRaster().getDataBuffer();
+ super(createArrayFromImage(image));
- this.width = this.image.getWidth();
- this.planeSize = width * this.image.getHeight();
-
- this.canUseDataBuffer = image.getRaster().getDataBuffer() instanceof DataBufferInt &&
- image.getRaster().getSampleModel() instanceof SinglePixelPackedSampleModel;
-
- this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
- }
-
- @Override
- public byte getValue(int index) {
- int channel = index / planeSize;
- int xyIndex = index % planeSize;
-
- int pixel = canUseDataBuffer ?
- dataBuffer.getElem(0, xyIndex) :
- image.getRGB(xyIndex % width, xyIndex / width);
-
- return switch (channel) {
- case 0 -> (byte) ColorTools.red(pixel);
- case 1 -> (byte) ColorTools.green(pixel);
- case 2 -> (byte) ColorTools.blue(pixel);
- default -> throw new IllegalArgumentException(String.format("The provided index %d is out of bounds", index));
- };
+ this.size = AccessTools.getSizeOfDataBufferInBytes(image.getRaster().getDataBuffer());
}
@Override
@@ -79,4 +51,47 @@ public int getSizeBytes() {
public boolean isValid() {
return true;
}
+
+ private static byte[] createArrayFromImage(BufferedImage image) {
+ Raster raster = image.getRaster();
+ int width = raster.getWidth();
+ int height = raster.getHeight();
+ int planeSize = width * height;
+ int numBands = 3;
+
+ byte[] array = new byte[planeSize * numBands];
+ if (raster.getSampleModel() instanceof SinglePixelPackedSampleModel && raster.getDataBuffer() instanceof DataBufferInt) {
+ DataBuffer dataBuffer = raster.getDataBuffer();
+
+ for (int b=0; b
- * This {@link ByteAccess} is immutable; any attempt to changes its values will result in a
+ * This {@link ByteArray} is immutable; any attempt to changes its values will result in a
* {@link UnsupportedOperationException}.
*
* This data access is marked as volatile but always contain valid data.
*/
-public class ByteRasterAccess implements ByteAccess, SizableDataAccess, VolatileAccess {
+public class ByteRasterAccess extends ByteArray implements SizableDataAccess, VolatileAccess {
- private final Raster raster;
- private final DataBuffer dataBuffer;
- private final int width;
- private final int planeSize;
- private final boolean canUseDataBuffer;
private final int size;
/**
@@ -32,28 +27,9 @@ public class ByteRasterAccess implements ByteAccess, SizableDataAccess, Volatile
* @throws NullPointerException if the provided image is null
*/
public ByteRasterAccess(Raster raster) {
- this.raster = raster;
- this.dataBuffer = this.raster.getDataBuffer();
+ super(createArrayFromRaster(raster));
- this.width = this.raster.getWidth();
- this.planeSize = width * this.raster.getHeight();
-
- this.canUseDataBuffer = this.dataBuffer instanceof DataBufferByte &&
- AccessTools.isSampleModelDirectlyUsable(this.raster);
-
- this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
- }
-
- @Override
- public byte getValue(int index) {
- int b = index / planeSize;
- int xyIndex = index % planeSize;
-
- if (canUseDataBuffer) {
- return (byte) dataBuffer.getElem(b, xyIndex);
- } else {
- return (byte) raster.getSample(xyIndex % width, xyIndex / width, b);
- }
+ this.size = AccessTools.getSizeOfDataBufferInBytes(raster.getDataBuffer());
}
@Override
@@ -70,4 +46,32 @@ public int getSizeBytes() {
public boolean isValid() {
return true;
}
+
+ private static byte[] createArrayFromRaster(Raster raster) {
+ int width = raster.getWidth();
+ int height = raster.getHeight();
+ int planeSize = width * height;
+ int numBands = raster.getNumBands();
+
+ byte[] array = new byte[planeSize * numBands];
+ if (AccessTools.isSampleModelDirectlyUsable(raster) && raster.getDataBuffer() instanceof DataBufferByte) {
+ DataBuffer dataBuffer = raster.getDataBuffer();
+
+ for (int b=0; b
* This data access is marked as volatile but always contain valid data.
*/
-public class DoubleRasterAccess implements DoubleAccess, SizableDataAccess, VolatileAccess {
+public class DoubleRasterAccess extends DoubleArray implements SizableDataAccess, VolatileAccess {
- private final Raster raster;
- private final DataBuffer dataBuffer;
- private final int width;
- private final int planeSize;
- private final boolean canUseDataBuffer;
private final int size;
/**
@@ -32,28 +27,9 @@ public class DoubleRasterAccess implements DoubleAccess, SizableDataAccess, Vola
* @throws NullPointerException if the provided image is null
*/
public DoubleRasterAccess(Raster raster) {
- this.raster = raster;
- this.dataBuffer = this.raster.getDataBuffer();
+ super(createArrayFromRaster(raster));
- this.width = this.raster.getWidth();
- this.planeSize = width * this.raster.getHeight();
-
- this.canUseDataBuffer = this.dataBuffer instanceof DataBufferDouble &&
- AccessTools.isSampleModelDirectlyUsable(this.raster);
-
- this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
- }
-
- @Override
- public double getValue(int index) {
- int b = index / planeSize;
- int xyIndex = index % planeSize;
-
- if (canUseDataBuffer) {
- return dataBuffer.getElemDouble(b, xyIndex);
- } else {
- return raster.getSampleDouble(xyIndex % width, xyIndex / width, b);
- }
+ this.size = AccessTools.getSizeOfDataBufferInBytes(raster.getDataBuffer());
}
@Override
@@ -70,4 +46,32 @@ public int getSizeBytes() {
public boolean isValid() {
return true;
}
+
+ private static double[] createArrayFromRaster(Raster raster) {
+ int width = raster.getWidth();
+ int height = raster.getHeight();
+ int planeSize = width * height;
+ int numBands = raster.getNumBands();
+
+ double[] array = new double[planeSize * numBands];
+ if (AccessTools.isSampleModelDirectlyUsable(raster) && raster.getDataBuffer() instanceof DataBufferDouble) {
+ DataBuffer dataBuffer = raster.getDataBuffer();
+
+ for (int b=0; b
* This data access is marked as volatile but always contain valid data.
*/
-public class FloatRasterAccess implements FloatAccess, SizableDataAccess, VolatileAccess {
+public class FloatRasterAccess extends FloatArray implements SizableDataAccess, VolatileAccess {
- private final Raster raster;
- private final DataBuffer dataBuffer;
- private final int width;
- private final int planeSize;
- private final boolean canUseDataBuffer;
private final int size;
/**
@@ -32,28 +27,9 @@ public class FloatRasterAccess implements FloatAccess, SizableDataAccess, Volati
* @throws NullPointerException if the provided image is null
*/
public FloatRasterAccess(Raster raster) {
- this.raster = raster;
- this.dataBuffer = this.raster.getDataBuffer();
+ super(createArrayFromRaster(raster));
- this.width = this.raster.getWidth();
- this.planeSize = width * this.raster.getHeight();
-
- this.canUseDataBuffer = this.dataBuffer instanceof DataBufferFloat &&
- AccessTools.isSampleModelDirectlyUsable(this.raster);
-
- this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
- }
-
- @Override
- public float getValue(int index) {
- int b = index / planeSize;
- int xyIndex = index % planeSize;
-
- if (canUseDataBuffer) {
- return dataBuffer.getElemFloat(b, xyIndex);
- } else {
- return raster.getSampleFloat(xyIndex % width, xyIndex / width, b);
- }
+ this.size = AccessTools.getSizeOfDataBufferInBytes(raster.getDataBuffer());
}
@Override
@@ -70,4 +46,32 @@ public int getSizeBytes() {
public boolean isValid() {
return true;
}
+
+ private static float[] createArrayFromRaster(Raster raster) {
+ int width = raster.getWidth();
+ int height = raster.getHeight();
+ int planeSize = width * height;
+ int numBands = raster.getNumBands();
+
+ float[] array = new float[planeSize * numBands];
+ if (AccessTools.isSampleModelDirectlyUsable(raster) && raster.getDataBuffer() instanceof DataBufferFloat) {
+ DataBuffer dataBuffer = raster.getDataBuffer();
+
+ for (int b=0; b
* This data access is marked as volatile but always contain valid data.
*/
-public class IntRasterAccess implements IntAccess, SizableDataAccess, VolatileAccess {
+public class IntRasterAccess extends IntArray implements SizableDataAccess, VolatileAccess {
- private final Raster raster;
- private final DataBuffer dataBuffer;
- private final int width;
- private final int planeSize;
- private final boolean canUseDataBuffer;
private final int size;
/**
* Create the int raster access.
*
* @param raster the raster containing the values to return. Its pixels are expected to be stored in the int format
- * @throws NullPointerException if the provided image is null
+ * @throws NullPointerException if the provided raster is null
*/
public IntRasterAccess(Raster raster) {
- this.raster = raster;
- this.dataBuffer = this.raster.getDataBuffer();
+ super(createArrayFromRaster(raster));
- this.width = this.raster.getWidth();
- this.planeSize = width * this.raster.getHeight();
-
- this.canUseDataBuffer = this.dataBuffer instanceof DataBufferInt &&
- AccessTools.isSampleModelDirectlyUsable(this.raster);
-
- this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
- }
-
- @Override
- public int getValue(int index) {
- int b = index / planeSize;
- int xyIndex = index % planeSize;
-
- if (canUseDataBuffer) {
- return dataBuffer.getElem(b, xyIndex);
- } else {
- return raster.getSample(xyIndex % width, xyIndex / width, b);
- }
+ this.size = AccessTools.getSizeOfDataBufferInBytes(raster.getDataBuffer());
}
@Override
@@ -70,4 +46,32 @@ public int getSizeBytes() {
public boolean isValid() {
return true;
}
+
+ private static int[] createArrayFromRaster(Raster raster) {
+ int width = raster.getWidth();
+ int height = raster.getHeight();
+ int planeSize = width * height;
+ int numBands = raster.getNumBands();
+
+ int[] array = new int[planeSize * numBands];
+ if (AccessTools.isSampleModelDirectlyUsable(raster) && raster.getDataBuffer() instanceof DataBufferInt) {
+ DataBuffer dataBuffer = raster.getDataBuffer();
+
+ for (int b=0; b
* This data access is marked as volatile but always contain valid data.
*/
-public class ShortRasterAccess implements ShortAccess, SizableDataAccess, VolatileAccess {
+public class ShortRasterAccess extends ShortArray implements SizableDataAccess, VolatileAccess {
- private final Raster raster;
- private final DataBuffer dataBuffer;
- private final int width;
- private final int planeSize;
- private final boolean canUseDataBuffer;
private final int size;
/**
@@ -33,28 +28,9 @@ public class ShortRasterAccess implements ShortAccess, SizableDataAccess, Volati
* @throws NullPointerException if the provided image is null
*/
public ShortRasterAccess(Raster raster) {
- this.raster = raster;
- this.dataBuffer = this.raster.getDataBuffer();
+ super(createArrayFromRaster(raster));
- this.width = this.raster.getWidth();
- this.planeSize = width * this.raster.getHeight();
-
- this.canUseDataBuffer = (this.dataBuffer instanceof DataBufferUShort || this.dataBuffer instanceof DataBufferShort) &&
- AccessTools.isSampleModelDirectlyUsable(this.raster);
-
- this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
- }
-
- @Override
- public short getValue(int index) {
- int b = index / planeSize;
- int xyIndex = index % planeSize;
-
- if (canUseDataBuffer) {
- return (short) dataBuffer.getElem(b, xyIndex);
- } else {
- return (short) raster.getSample(xyIndex % width, xyIndex / width, b);
- }
+ this.size = AccessTools.getSizeOfDataBufferInBytes(raster.getDataBuffer());
}
@Override
@@ -71,4 +47,32 @@ public int getSizeBytes() {
public boolean isValid() {
return true;
}
+
+ private static short[] createArrayFromRaster(Raster raster) {
+ int width = raster.getWidth();
+ int height = raster.getHeight();
+ int planeSize = width * height;
+ int numBands = raster.getNumBands();
+
+ short[] array = new short[planeSize * numBands];
+ if (AccessTools.isSampleModelDirectlyUsable(raster) && (raster.getDataBuffer() instanceof DataBufferUShort || raster.getDataBuffer() instanceof DataBufferShort)) {
+ DataBuffer dataBuffer = raster.getDataBuffer();
+
+ for (int b=0; b