Skip to content

Commit

Permalink
Thumbnail size
Browse files Browse the repository at this point in the history
  • Loading branch information
Rylern committed Sep 12, 2024
1 parent ed297c8 commit 87702d4
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 10 deletions.
23 changes: 17 additions & 6 deletions src/main/java/qupath/ext/omero/core/apis/ApisHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
public class ApisHandler implements AutoCloseable {

private static final Logger logger = LoggerFactory.getLogger(ApisHandler.class);
private static final int THUMBNAIL_SIZE = 256;
private static final int THUMBNAIL_CACHE_SIZE = 1000;
private static final Map<String, PixelType> PIXEL_TYPE_MAP = Map.of(
"uint8", PixelType.UINT8,
Expand All @@ -66,11 +67,12 @@ public class ApisHandler implements AutoCloseable {
private final WebGatewayApi webGatewayApi;
private final IViewerApi iViewerApi;
private final BooleanProperty areOrphanedImagesLoading = new SimpleBooleanProperty(false);
private final Cache<Long, CompletableFuture<Optional<BufferedImage>>> thumbnailsCache = CacheBuilder.newBuilder()
private final Cache<IdSizeWrapper, CompletableFuture<Optional<BufferedImage>>> thumbnailsCache = CacheBuilder.newBuilder()
.maximumSize(THUMBNAIL_CACHE_SIZE)
.build();
private final Map<Class<? extends RepositoryEntity>, BufferedImage> omeroIconsCache = new ConcurrentHashMap<>();
private final boolean canSkipAuthentication;
private record IdSizeWrapper(long id, int size) {}

private ApisHandler(URI host, JsonApi jsonApi, boolean canSkipAuthentication) {
this.host = host;
Expand Down Expand Up @@ -492,19 +494,28 @@ public CompletableFuture<Optional<BufferedImage>> getOmeroIcon(Class<? extends R
}

/**
* See {@link WebGatewayApi#getThumbnail(long)}.
* Thumbnails are cached in a cache of size {@link #THUMBNAIL_CACHE_SIZE}.
* {@link #getThumbnail(long, int)} with a size of
* {@link #THUMBNAIL_SIZE}.
*/
public CompletableFuture<Optional<BufferedImage>> getThumbnail(long id) {
return getThumbnail(id, THUMBNAIL_SIZE);
}

/**
* See {@link WebGatewayApi#getThumbnail(long, int)}.
* Thumbnails are cached in a cache of size {@link #THUMBNAIL_CACHE_SIZE}.
*/
public CompletableFuture<Optional<BufferedImage>> getThumbnail(long id, int size) {
try {
IdSizeWrapper key = new IdSizeWrapper(id, size);
CompletableFuture<Optional<BufferedImage>> request = thumbnailsCache.get(
id,
() -> webGatewayApi.getThumbnail(id)
key,
() -> webGatewayApi.getThumbnail(id, size)
);

request.thenAccept(response -> {
if (response.isEmpty()) {
thumbnailsCache.invalidate(id);
thumbnailsCache.invalidate(key);
}
});
return request;
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/qupath/ext/omero/core/apis/WebGatewayApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class WebGatewayApi {
private static final String PROJECT_ICON_NAME = "folder16.png";
private static final String DATASET_ICON_NAME = "folder_image16.png";
private static final String ORPHANED_FOLDER_ICON_NAME = "folder_yellow16.png";
private static final String THUMBNAIL_URL = "%s/webgateway/render_thumbnail/%d";
private static final String THUMBNAIL_URL = "%s/webgateway/render_thumbnail/%d/%d";
private static final String IMAGE_DATA_URL = "%s/webgateway/imgData/%d";
private static final String TILE_URL = "%s/webgateway/render_image_region/%d/%d/%d/?" +
"tile=%d,%d,%d,%d,%d" +
Expand Down Expand Up @@ -110,12 +110,13 @@ public CompletableFuture<Optional<BufferedImage>> getOrphanedFolderIcon() {
* <p>This function is asynchronous.</p>
*
* @param id the OMERO image ID
* @param size the max width and max height the thumbnail should have
* @return a CompletableFuture with the thumbnail, or an empty Optional if an error occurred
*/
public CompletableFuture<Optional<BufferedImage>> getThumbnail(long id) {
public CompletableFuture<Optional<BufferedImage>> getThumbnail(long id, int size) {
changeNumberOfThumbnailsLoading(true);

return ApiUtilities.getImage(String.format(THUMBNAIL_URL, host, id)).thenApply(thumbnail -> {
return ApiUtilities.getImage(String.format(THUMBNAIL_URL, host, id, size)).thenApply(thumbnail -> {
changeNumberOfThumbnailsLoading(false);
return thumbnail;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,28 @@ protected BufferedImage readTile(TileRequest tileRequest) throws IOException {
return pixelAPIReader.readTile(tileRequest);
}

@Override
public BufferedImage getDefaultThumbnail(int z, int t) throws IOException {
Optional<BufferedImage> thumbnail = Optional.empty();

if (isRGB()) {
try {
thumbnail = client.getApisHandler().getThumbnail(
id,
Math.max(originalMetadata.getLevel(0).getWidth(), originalMetadata.getLevel(0).getHeight())
).get();
} catch (InterruptedException | ExecutionException e) {
throw new IOException(e);
}
}

if (thumbnail.isPresent()) {
return thumbnail.get();
} else {
return super.getDefaultThumbnail(z, t);
}
}

@Override
protected ImageServerBuilder.ServerBuilder<BufferedImage> createServerBuilder() {
return ImageServerBuilder.DefaultImageServerBuilder.createInstance(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public Image(WebClient client, URI imageUri) throws IOException {
image.ifPresent(value -> name.setText(value.getLabel().get()))
));

client.getApisHandler().getThumbnail(imageID.getAsLong()).thenAccept(thumbnail -> Platform.runLater(() ->
client.getApisHandler().getThumbnail(imageID.getAsLong(), (int) thumbnail.getWidth()).thenAccept(thumbnail -> Platform.runLater(() ->
thumbnail.ifPresent(bufferedImage -> UiUtilities.paintBufferedImageOnCanvas(bufferedImage, this.thumbnail))
));
}
Expand Down
11 changes: 11 additions & 0 deletions src/test/java/qupath/ext/omero/core/apis/TestApisHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,17 @@ void Check_Image_Thumbnail() throws ExecutionException, InterruptedException {
Assertions.assertNotNull(image);
}

@Test
void Check_Image_Thumbnail_With_Specific_Size() throws ExecutionException, InterruptedException {
long imageId = OmeroServer.getComplexImage().getId();
int size = 30;

BufferedImage image = apisHandler.getThumbnail(imageId, size).get().orElse(null);

Assertions.assertNotNull(image);
Assertions.assertEquals(size, Math.max(image.getWidth(), image.getHeight()));
}

@Test
void Check_Image_Thumbnail_With_Invalid_Image_ID() throws ExecutionException, InterruptedException {
long invalidImageID = -1;
Expand Down

0 comments on commit 87702d4

Please sign in to comment.