Thanks for relicensing the library! I wanted to write an isyntax -> tiff converter using libtiff. I came up with this:
#include "libisyntax.h"
#include <stdint.h>
#include <assert.h>
#include "tiffio.h"
#include <string.h>
#define LOG_VAR(fmt, var) printf("%s: %s=" fmt "\n", __FUNCTION__, #var, var)
uint32_t bgra_to_rgba(uint32_t val) {
return ((val & 0xff) << 16) | (val & 0x00ff00) | ((val & 0xff0000) >> 16) | (val & 0xff000000);
}
void write_pyramid_level(isyntax_t* isyntax, isyntax_cache_t *isyntax_cache, isyntax_level_t* level, TIFF* output_tiff, int32_t tile_size, int32_t num_channels) {
int32_t num_tiles_x = libisyntax_level_get_width_in_tiles(level);
int32_t num_tiles_y = libisyntax_level_get_height_in_tiles(level);
int32_t width = tile_size * libisyntax_level_get_width_in_tiles(level);
int32_t height = tile_size * libisyntax_level_get_height_in_tiles(level);
int32_t scale = libisyntax_level_get_scale(level);
// TODO: Compute the spacing
TIFFSetField(output_tiff, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(output_tiff, TIFFTAG_IMAGELENGTH, height);
for (uint32_t tile_y = 0; tile_y < num_tiles_y; ++tile_y) {
for (uint32_t tile_x = 0; tile_x < num_tiles_x; ++tile_x) {
// Let's print some progress for each percentage of the image that we have processed
int32_t progress = (int32_t) (100.0 * (tile_y * num_tiles_x + tile_x) / (num_tiles_x * num_tiles_y));
if (progress % 5 == 0) {
printf("Progress: %d%%\r", progress);
fflush(stdout);
}
uint32_t *pixels = NULL;
assert(libisyntax_tile_read(isyntax, isyntax_cache, scale, tile_x, tile_y, &pixels) == LIBISYNTAX_OK);
// convert data to the correct pixel format (bgra->rgba).
for (int i = 0; i < tile_size * tile_size; ++i) {
pixels[i] = bgra_to_rgba(pixels[i]);
}
// Copy the tile data to the output buffer
uint32_t tile_width = (tile_x < num_tiles_x - 1) ? tile_size : (width % tile_size);
uint32_t tile_height = (tile_y < num_tiles_y - 1) ? tile_size : (height % tile_size);
if (tile_x == num_tiles_x - 1 || tile_y == num_tiles_y - 1) {
// TODO: Not sure we need to adjust here for the border tiles?
// Create a new buffer of the correct size based on the adjusted tile_width and tile_height
unsigned char *buf = (unsigned char *)_TIFFmalloc(tile_size * tile_size * num_channels);
// Copy the relevant data from the original buffer (pixels) to the new buffer
for (uint32_t y = 0; y < tile_height; ++y) {
memcpy(buf + y * tile_size * num_channels, pixels + y * tile_width * num_channels, tile_width * num_channels);
}
TIFFWriteTile(output_tiff, buf, tile_x * tile_size, tile_y * tile_size, 0, 0);
// Free the adjusted buffer
_TIFFfree(buf);
} else {
// Pass the original buffer (pixels) to TIFFWriteTile
TIFFWriteTile(output_tiff, pixels, tile_x * tile_size, tile_y * tile_size, 0, 0);
}
libisyntax_tile_free_pixels(pixels);
}
}
}
int main(int argc, char** argv) {
if (argc <= 1) {
printf("Usage: %s <isyntax_file> <output.tiff> - convert an isyntax image to a tiff.", argv[0]);
return 0;
}
char* filename = argv[1];
libisyntax_init();
isyntax_t* isyntax;
if (libisyntax_open(filename, /*is_init_allocators=*/0, &isyntax) != LIBISYNTAX_OK) {
fprintf(stderr, "Failed to open %s\n", filename);
return -1;
}
printf("Successfully opened %s\n", filename);
TIFF *output_tiff = TIFFOpen(argv[2], "w8");
if (!output_tiff) {
fprintf(stderr, "Failed to open output TIFF file\n");
libisyntax_close(isyntax);
return 1;
}
LOG_VAR("%s", argv[2]);
int32_t tile_width = libisyntax_get_tile_width(isyntax);
int32_t tile_height = libisyntax_get_tile_height(isyntax);
LOG_VAR("%d", tile_width);
LOG_VAR("%d", tile_height);
isyntax_cache_t *isyntax_cache = NULL;
assert(libisyntax_cache_create("tiff conversion cache", 2000, &isyntax_cache) == LIBISYNTAX_OK);
assert(libisyntax_cache_inject(isyntax_cache, isyntax) == LIBISYNTAX_OK);
int wsi_image_idx = libisyntax_get_wsi_image_index(isyntax);
const isyntax_image_t* wsi_image = libisyntax_get_image(isyntax, wsi_image_idx);
int32_t num_levels = libisyntax_image_get_level_count(wsi_image);
int32_t num_channels = 4;
int32_t bits_per_sample = 8;
int32_t quality = 70;
TIFFSetField(output_tiff, TIFFTAG_SAMPLESPERPIXEL, num_channels);
TIFFSetField(output_tiff, TIFFTAG_BITSPERSAMPLE, bits_per_sample);
TIFFSetField(output_tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(output_tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(output_tiff, TIFFTAG_TILEWIDTH, tile_width);
TIFFSetField(output_tiff, TIFFTAG_TILELENGTH, tile_height);
TIFFSetField(output_tiff, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
TIFFSetField(output_tiff, TIFFTAG_JPEGQUALITY, quality);
assert(tile_width == tile_height);
for (int32_t level_idx = 0; level_idx < num_levels; ++level_idx) {
LOG_VAR("%d", level_idx);
isyntax_level_t* current_level = libisyntax_image_get_level(wsi_image, level_idx);
write_pyramid_level(isyntax, isyntax_cache,current_level, output_tiff, tile_width, num_channels);
if (level_idx < num_levels - 1) {
TIFFWriteDirectory(output_tiff);
}
}
// Close the iSyntax file and the TIFF file
TIFFClose(output_tiff);
libisyntax_cache_destroy(isyntax_cache);
libisyntax_close(isyntax);
return 0;
}
However, this is very slow, and my profiler tells me a major part is actually in the read_tile. Am I using the library as intended here?
Hi,
Thanks for relicensing the library! I wanted to write an isyntax -> tiff converter using libtiff. I came up with this:
However, this is very slow, and my profiler tells me a major part is actually in the
read_tile. Am I using the library as intended here?