Skip to content

Commit dc925ac

Browse files
authored
Merge pull request #20 from qupath/array-accesses
Make all accesses implement ArrayDataAccess
2 parents c516821 + a70e858 commit dc925ac

15 files changed

Lines changed: 281 additions & 248 deletions

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66
group = "io.github.qupath"
7-
version = "0.1.1"
7+
version = "0.1.2"
88

99
repositories {
1010
mavenCentral()

settings.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ pluginManagement {
1010
rootProject.name = "qupath-imglib2"
1111

1212
// Used for version catalogs (including Java compatibility)
13-
val qupathVersion = "0.6.0"
14-
val sciJavaVersion = "43.0.0"
13+
val qupathVersion = "0.7.0"
14+
val sciJavaVersion = "44.0.0"
1515

1616
dependencyResolutionManagement {
1717

@@ -28,8 +28,8 @@ dependencyResolutionManagement {
2828
}
2929

3030
repositories {
31-
maven("https://maven.scijava.org/content/groups/public/")
3231
mavenCentral()
32+
maven("https://maven.scijava.org/content/groups/public/")
3333
}
3434

3535
}

src/main/java/qupath/ext/imglib2/accesses/AccessTools.java

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,16 @@ public static boolean isSampleModelDirectlyUsable(Raster raster) {
4545
* @return the size of the provided data buffer in bytes
4646
*/
4747
public static int getSizeOfDataBufferInBytes(DataBuffer dataBuffer) {
48-
int bytesPerPixel;
49-
if (dataBuffer instanceof DataBufferByte) {
50-
bytesPerPixel = 1;
51-
} else if (dataBuffer instanceof DataBufferShort || dataBuffer instanceof DataBufferUShort) {
52-
bytesPerPixel = 2;
53-
} else if (dataBuffer instanceof DataBufferInt || dataBuffer instanceof DataBufferFloat) {
54-
bytesPerPixel = 4;
55-
} else if (dataBuffer instanceof DataBufferDouble) {
56-
bytesPerPixel = 8;
57-
} else {
58-
logger.warn("Unexpected data buffer {}. Considering each element of it takes 1 byte", dataBuffer);
59-
bytesPerPixel = 1;
60-
}
48+
int bytesPerPixel = switch (dataBuffer) {
49+
case DataBufferByte _ -> 1;
50+
case DataBufferShort _, DataBufferUShort _ -> 2;
51+
case DataBufferInt _, DataBufferFloat _ -> 4;
52+
case DataBufferDouble _ -> 8;
53+
default -> {
54+
logger.warn("Unexpected data buffer {}. Considering each element of it takes 1 byte", dataBuffer);
55+
yield 1;
56+
}
57+
};
6158

6259
return bytesPerPixel * dataBuffer.getSize() * dataBuffer.getNumBanks();
6360
}

src/main/java/qupath/ext/imglib2/accesses/ArgbBufferedImageAccess.java

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
11
package qupath.ext.imglib2.accesses;
22

3-
import net.imglib2.img.basictypeaccess.IntAccess;
3+
import net.imglib2.img.basictypeaccess.array.IntArray;
44
import net.imglib2.img.basictypeaccess.volatiles.VolatileAccess;
55
import qupath.ext.imglib2.SizableDataAccess;
66
import qupath.lib.common.ColorTools;
77

88
import java.awt.image.BufferedImage;
99
import java.awt.image.DataBuffer;
1010
import java.awt.image.DataBufferInt;
11+
import java.awt.image.Raster;
1112
import java.awt.image.SinglePixelPackedSampleModel;
1213

1314
/**
14-
* An {@link IntAccess} whose elements are computed from an (A)RGB {@link BufferedImage}.
15+
* An {@link IntArray} whose elements are computed from an (A)RGB {@link BufferedImage}.
1516
* <p>
1617
* If the alpha component is not provided (e.g. if the {@link BufferedImage} has the {@link BufferedImage#TYPE_INT_RGB} type),
1718
* then the alpha component of each pixel is considered to be 255.
1819
* <p>
19-
* This {@link IntAccess} is immutable; any attempt to changes its values will result in a
20+
* This {@link IntArray} is immutable; any attempt to changes its values will result in a
2021
* {@link UnsupportedOperationException}.
2122
* <p>
2223
* This data access is marked as volatile but always contain valid data.
2324
*/
24-
public class ArgbBufferedImageAccess implements IntAccess, SizableDataAccess, VolatileAccess {
25+
public class ArgbBufferedImageAccess extends IntArray implements SizableDataAccess, VolatileAccess {
2526

26-
private final BufferedImage image;
27-
private final DataBuffer dataBuffer;
28-
private final int width;
29-
private final int planeSize;
30-
private final boolean canUseDataBuffer;
31-
private final boolean alphaProvided;
3227
private final int size;
3328

3429
/**
@@ -38,39 +33,45 @@ public class ArgbBufferedImageAccess implements IntAccess, SizableDataAccess, Vo
3833
* @throws NullPointerException if the provided image is null
3934
*/
4035
public ArgbBufferedImageAccess(BufferedImage image) {
41-
this.image = image;
42-
this.dataBuffer = this.image.getRaster().getDataBuffer();
36+
super(createArrayFromImage(image));
4337

44-
this.width = this.image.getWidth();
45-
this.planeSize = width * this.image.getHeight();
46-
47-
this.canUseDataBuffer = image.getRaster().getDataBuffer() instanceof DataBufferInt &&
48-
image.getRaster().getSampleModel() instanceof SinglePixelPackedSampleModel;
49-
this.alphaProvided = image.getType() == BufferedImage.TYPE_INT_ARGB;
50-
51-
this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
38+
this.size = AccessTools.getSizeOfDataBufferInBytes(image.getRaster().getDataBuffer());
5239
}
5340

54-
@Override
55-
public int getValue(int index) {
56-
int xyIndex = index % planeSize;
41+
private static int[] createArrayFromImage(BufferedImage image) {
42+
Raster raster = image.getRaster();
43+
int width = raster.getWidth();
44+
int height = raster.getHeight();
45+
int planeSize = width * height;
5746

58-
if (canUseDataBuffer) {
59-
int pixel = dataBuffer.getElem(0, xyIndex);
47+
int[] array = new int[planeSize];
48+
if (raster.getSampleModel() instanceof SinglePixelPackedSampleModel && raster.getDataBuffer() instanceof DataBufferInt) {
49+
DataBuffer dataBuffer = raster.getDataBuffer();
50+
boolean alphaProvided = image.getType() == BufferedImage.TYPE_INT_ARGB;
6051

61-
if (alphaProvided) {
62-
return pixel;
63-
} else {
64-
return ColorTools.packARGB(
65-
255,
66-
ColorTools.red(pixel),
67-
ColorTools.green(pixel),
68-
ColorTools.blue(pixel)
69-
);
52+
for (int i=0; i<planeSize; i++) {
53+
int pixel = dataBuffer.getElem(0, i);
54+
55+
if (alphaProvided) {
56+
array[i] = pixel;
57+
} else {
58+
array[i] = ColorTools.packARGB(
59+
255,
60+
ColorTools.red(pixel),
61+
ColorTools.green(pixel),
62+
ColorTools.blue(pixel)
63+
);
64+
}
7065
}
7166
} else {
72-
return image.getRGB(xyIndex % width, xyIndex / width);
67+
for (int y=0; y<height; y++) {
68+
for (int x=0; x<width; x++) {
69+
array[x + y * width] = image.getRGB(x, y);
70+
}
71+
}
7372
}
73+
74+
return array;
7475
}
7576

7677
@Override
Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,28 @@
11
package qupath.ext.imglib2.accesses;
22

3-
import net.imglib2.img.basictypeaccess.ByteAccess;
3+
import net.imglib2.img.basictypeaccess.array.ByteArray;
44
import net.imglib2.img.basictypeaccess.volatiles.VolatileAccess;
55
import qupath.ext.imglib2.SizableDataAccess;
66
import qupath.lib.common.ColorTools;
77

88
import java.awt.image.BufferedImage;
99
import java.awt.image.DataBuffer;
1010
import java.awt.image.DataBufferInt;
11+
import java.awt.image.Raster;
1112
import java.awt.image.SinglePixelPackedSampleModel;
1213

1314
/**
14-
* An {@link ByteAccess} whose elements are computed from an RGB {@link BufferedImage}.
15+
* An {@link ByteArray} whose elements are computed from an RGB {@link BufferedImage}.
1516
* <p>
1617
* The alpha component is not taken into account.
1718
* <p>
18-
* This {@link ByteAccess} is immutable; any attempt to changes its values will result in a
19+
* This {@link ByteArray} is immutable; any attempt to changes its values will result in a
1920
* {@link UnsupportedOperationException}.
2021
* <p>
2122
* This data access is marked as volatile but always contain valid data.
2223
*/
23-
public class ByteBufferedImageAccess implements ByteAccess, SizableDataAccess, VolatileAccess {
24+
public class ByteBufferedImageAccess extends ByteArray implements SizableDataAccess, VolatileAccess {
2425

25-
private final BufferedImage image;
26-
private final DataBuffer dataBuffer;
27-
private final int width;
28-
private final int planeSize;
29-
private final boolean canUseDataBuffer;
3026
private final int size;
3127

3228
/**
@@ -36,33 +32,9 @@ public class ByteBufferedImageAccess implements ByteAccess, SizableDataAccess, V
3632
* @throws NullPointerException if the provided image is null
3733
*/
3834
public ByteBufferedImageAccess(BufferedImage image) {
39-
this.image = image;
40-
this.dataBuffer = this.image.getRaster().getDataBuffer();
35+
super(createArrayFromImage(image));
4136

42-
this.width = this.image.getWidth();
43-
this.planeSize = width * this.image.getHeight();
44-
45-
this.canUseDataBuffer = image.getRaster().getDataBuffer() instanceof DataBufferInt &&
46-
image.getRaster().getSampleModel() instanceof SinglePixelPackedSampleModel;
47-
48-
this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
49-
}
50-
51-
@Override
52-
public byte getValue(int index) {
53-
int channel = index / planeSize;
54-
int xyIndex = index % planeSize;
55-
56-
int pixel = canUseDataBuffer ?
57-
dataBuffer.getElem(0, xyIndex) :
58-
image.getRGB(xyIndex % width, xyIndex / width);
59-
60-
return switch (channel) {
61-
case 0 -> (byte) ColorTools.red(pixel);
62-
case 1 -> (byte) ColorTools.green(pixel);
63-
case 2 -> (byte) ColorTools.blue(pixel);
64-
default -> throw new IllegalArgumentException(String.format("The provided index %d is out of bounds", index));
65-
};
37+
this.size = AccessTools.getSizeOfDataBufferInBytes(image.getRaster().getDataBuffer());
6638
}
6739

6840
@Override
@@ -79,4 +51,47 @@ public int getSizeBytes() {
7951
public boolean isValid() {
8052
return true;
8153
}
54+
55+
private static byte[] createArrayFromImage(BufferedImage image) {
56+
Raster raster = image.getRaster();
57+
int width = raster.getWidth();
58+
int height = raster.getHeight();
59+
int planeSize = width * height;
60+
int numBands = 3;
61+
62+
byte[] array = new byte[planeSize * numBands];
63+
if (raster.getSampleModel() instanceof SinglePixelPackedSampleModel && raster.getDataBuffer() instanceof DataBufferInt) {
64+
DataBuffer dataBuffer = raster.getDataBuffer();
65+
66+
for (int b=0; b<numBands; b++) {
67+
for (int i=0; i<planeSize; i++) {
68+
int pixel = dataBuffer.getElem(0, i);
69+
70+
array[i + b * planeSize] = (byte) switch (b) {
71+
case 0 -> ColorTools.red(pixel);
72+
case 1 -> ColorTools.green(pixel);
73+
case 2 -> ColorTools.blue(pixel);
74+
default -> throw new IllegalArgumentException(String.format("The provided channel %d is out of bounds", b));
75+
};
76+
}
77+
}
78+
} else {
79+
for (int b=0; b<numBands; b++) {
80+
for (int y=0; y<height; y++) {
81+
for (int x=0; x<width; x++) {
82+
int pixel = image.getRGB(x, y);
83+
84+
array[x + y * width + b * planeSize] = (byte) switch (b) {
85+
case 0 -> ColorTools.red(pixel);
86+
case 1 -> ColorTools.green(pixel);
87+
case 2 -> ColorTools.blue(pixel);
88+
default -> throw new IllegalArgumentException(String.format("The provided channel %d is out of bounds", b));
89+
};
90+
}
91+
}
92+
}
93+
}
94+
95+
return array;
96+
}
8297
}
Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package qupath.ext.imglib2.accesses;
22

3-
import net.imglib2.img.basictypeaccess.ByteAccess;
3+
import net.imglib2.img.basictypeaccess.array.ByteArray;
44
import net.imglib2.img.basictypeaccess.volatiles.VolatileAccess;
55
import qupath.ext.imglib2.SizableDataAccess;
66

@@ -9,20 +9,15 @@
99
import java.awt.image.Raster;
1010

1111
/**
12-
* A {@link ByteAccess} whose elements are computed from a {@link Raster}.
12+
* A {@link ByteArray} whose elements are computed from a {@link Raster}.
1313
* <p>
14-
* This {@link ByteAccess} is immutable; any attempt to changes its values will result in a
14+
* This {@link ByteArray} is immutable; any attempt to changes its values will result in a
1515
* {@link UnsupportedOperationException}.
1616
* <p>
1717
* This data access is marked as volatile but always contain valid data.
1818
*/
19-
public class ByteRasterAccess implements ByteAccess, SizableDataAccess, VolatileAccess {
19+
public class ByteRasterAccess extends ByteArray implements SizableDataAccess, VolatileAccess {
2020

21-
private final Raster raster;
22-
private final DataBuffer dataBuffer;
23-
private final int width;
24-
private final int planeSize;
25-
private final boolean canUseDataBuffer;
2621
private final int size;
2722

2823
/**
@@ -32,28 +27,9 @@ public class ByteRasterAccess implements ByteAccess, SizableDataAccess, Volatile
3227
* @throws NullPointerException if the provided image is null
3328
*/
3429
public ByteRasterAccess(Raster raster) {
35-
this.raster = raster;
36-
this.dataBuffer = this.raster.getDataBuffer();
30+
super(createArrayFromRaster(raster));
3731

38-
this.width = this.raster.getWidth();
39-
this.planeSize = width * this.raster.getHeight();
40-
41-
this.canUseDataBuffer = this.dataBuffer instanceof DataBufferByte &&
42-
AccessTools.isSampleModelDirectlyUsable(this.raster);
43-
44-
this.size = AccessTools.getSizeOfDataBufferInBytes(this.dataBuffer);
45-
}
46-
47-
@Override
48-
public byte getValue(int index) {
49-
int b = index / planeSize;
50-
int xyIndex = index % planeSize;
51-
52-
if (canUseDataBuffer) {
53-
return (byte) dataBuffer.getElem(b, xyIndex);
54-
} else {
55-
return (byte) raster.getSample(xyIndex % width, xyIndex / width, b);
56-
}
32+
this.size = AccessTools.getSizeOfDataBufferInBytes(raster.getDataBuffer());
5733
}
5834

5935
@Override
@@ -70,4 +46,32 @@ public int getSizeBytes() {
7046
public boolean isValid() {
7147
return true;
7248
}
49+
50+
private static byte[] createArrayFromRaster(Raster raster) {
51+
int width = raster.getWidth();
52+
int height = raster.getHeight();
53+
int planeSize = width * height;
54+
int numBands = raster.getNumBands();
55+
56+
byte[] array = new byte[planeSize * numBands];
57+
if (AccessTools.isSampleModelDirectlyUsable(raster) && raster.getDataBuffer() instanceof DataBufferByte) {
58+
DataBuffer dataBuffer = raster.getDataBuffer();
59+
60+
for (int b=0; b<numBands; b++) {
61+
for (int i=0; i<planeSize; i++) {
62+
array[i + b * planeSize] = (byte) dataBuffer.getElem(b, i);
63+
}
64+
}
65+
} else {
66+
for (int b=0; b<numBands; b++) {
67+
for (int y=0; y<height; y++) {
68+
for (int x=0; x<width; x++) {
69+
array[x + y * width + b * planeSize] = (byte) raster.getSample(x, y, b);
70+
}
71+
}
72+
}
73+
}
74+
75+
return array;
76+
}
7377
}

0 commit comments

Comments
 (0)