Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c62ec8b
Added first version for this isyntax_to_tiff
jonasteuwen Apr 17, 2023
0441a1e
Added NEON versions
jonasteuwen Apr 18, 2023
44df0ec
platform.c
jonasteuwen Apr 18, 2023
9bd41a7
Add read_region function
jonasteuwen Apr 18, 2023
b63971b
Compute bounds correctly...
jonasteuwen Apr 18, 2023
a721431
Take offset into account
jonasteuwen Apr 18, 2023
4ce5d12
- Make SIMD function also process sizes not divisible by 4.
jonasteuwen Apr 18, 2023
ef34a0d
Refactor BGRA to RGBA function.
jonasteuwen Apr 18, 2023
3988f23
Skip empty tiles
jonasteuwen Apr 19, 2023
751cb94
Improve offset computation
jonasteuwen Apr 19, 2023
3767301
Compute offset differently (and fix rgb conversion in example)
jonasteuwen Apr 19, 2023
5b34dde
Reformat code slightly
jonasteuwen Apr 19, 2023
aa4c4f6
Check some bounds:
jonasteuwen Apr 19, 2023
4e5e890
Additions:
jonasteuwen Apr 20, 2023
bd4e6c3
Initial version of isyntax -> tiff
jonasteuwen Apr 20, 2023
4cbb72a
Update tool
jonasteuwen Apr 20, 2023
4e7e1aa
Global eta makes more sense
jonasteuwen Apr 20, 2023
c450e5c
Cleanup tiff utility
jonasteuwen Apr 20, 2023
77745a6
Fix offset for level 0
jonasteuwen Apr 20, 2023
061053d
Add usage string
jonasteuwen Apr 20, 2023
82d6b57
Fix cache size (is it kilobytes?)
jonasteuwen Apr 20, 2023
b350af3
Fix formatting
jonasteuwen Apr 20, 2023
4e6a64d
Merge branch 'main' of github.com:NKI-AI/libisyntax
jonasteuwen Apr 20, 2023
863eba6
Fix conflicts
jonasteuwen Apr 20, 2023
05a7f57
Updated CMakeLists.txt
jonasteuwen Apr 20, 2023
f2a564c
Merge branch 'main' of github.com:NKI-AI/libisyntax
jonasteuwen Apr 20, 2023
64d70dd
Add read_region function
jonasteuwen Apr 18, 2023
ad9f4d9
Compute bounds correctly...
jonasteuwen Apr 18, 2023
69d37e9
Take offset into account
jonasteuwen Apr 18, 2023
1fba046
- Make SIMD function also process sizes not divisible by 4.
jonasteuwen Apr 18, 2023
e006cea
Refactor BGRA to RGBA function.
jonasteuwen Apr 18, 2023
9edcfcc
Skip empty tiles
jonasteuwen Apr 19, 2023
345a913
Improve offset computation
jonasteuwen Apr 19, 2023
5612d5a
Compute offset differently (and fix rgb conversion in example)
jonasteuwen Apr 19, 2023
e1d9666
Reformat code slightly
jonasteuwen Apr 19, 2023
3319ae0
Check some bounds:
jonasteuwen Apr 19, 2023
4c239e6
Additions:
jonasteuwen Apr 20, 2023
1ed0185
Initial version of isyntax -> tiff
jonasteuwen Apr 20, 2023
93abd48
Update tool
jonasteuwen Apr 20, 2023
141d567
Global eta makes more sense
jonasteuwen Apr 20, 2023
7ddb61a
Fix offset for level 0
jonasteuwen Apr 20, 2023
fd214a6
Updated CMakeLists.txt
jonasteuwen Apr 20, 2023
663af1e
Global eta makes more sense
jonasteuwen Apr 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 49 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ include_directories("${CMAKE_SOURCE_DIR}/src/utils")
include_directories("${CMAKE_SOURCE_DIR}/src/isyntax")
include_directories("${CMAKE_SOURCE_DIR}/src/third_party")

# Find LibTIFF library
find_package(TIFF REQUIRED)
if (NOT TIFF_FOUND)
message(WARNING "LibTIFF not found")
message(WARNING "Will not compile `isyntax-to-tiff` utility")
endif()
include_directories(${TIFF_INCLUDE_DIR})
find_package(Threads REQUIRED)
if (UNIX AND NOT APPLE) # needed for sem_wait, etc.
find_library(RT_LIBRARY rt)
set(EXTRA_LIBS ${RT_LIBRARY})
elseif (APPLE)
# No extra libraries needed for macOS
elseif (WIN32)
# No extra libraries needed for Windows
endif ()



set(LIBISYNTAX_COMMON_SOURCE_FILES
src/libisyntax.c
src/isyntax/isyntax.c
Expand All @@ -34,6 +53,7 @@ set(LIBISYNTAX_COMMON_SOURCE_FILES
src/third_party/ltalloc.cc
)


if (WIN32)
set(LIBISYNTAX_COMMON_SOURCE_FILES ${LIBISYNTAX_COMMON_SOURCE_FILES} src/platform/win32_utils.c)
else()
Expand All @@ -49,9 +69,35 @@ add_executable(isyntax_example
${LIBISYNTAX_COMMON_SOURCE_FILES}
)



add_executable(isyntax_example2
src/isyntax_example2.c
${LIBISYNTAX_COMMON_SOURCE_FILES}
)

if (TIFF_FOUND)
message(STATUS "Will compile `isyntax-to-tiff` utility")
add_executable(isyntax-to-tiff
src/isyntax_to_tiff.c
${LIBISYNTAX_COMMON_SOURCE_FILES} ${TIFF_LIBRARIES})

endif()

target_include_directories(isyntax-to-tiff PRIVATE ${TIFF_INCLUDE_DIRS})

if (WIN32)
target_link_libraries(libisyntax winmm)
target_link_libraries(isyntax_example winmm)
else()
target_link_libraries(libisyntax winmm Threads::Threads)
target_link_libraries(isyntax_example winmm Threads::Threads)
target_link_libraries(isyntax_example2 winmm Threads::Threads)
target_link_libraries(isyntax-to-tiff winmm Threads::Threads)


else()
target_link_libraries(libisyntax Threads::Threads ${EXTRA_LIBS})
target_link_libraries(isyntax_example Threads::Threads ${EXTRA_LIBS})
target_link_libraries(isyntax_example2 Threads::Threads ${EXTRA_LIBS})
if (TIFF_FOUND)
target_link_libraries(isyntax-to-tiff PRIVATE ${TIFF_LIBRARIES} Threads::Threads ${EXTRA_LIBS})
endif()
endif()
48 changes: 43 additions & 5 deletions src/isyntax/isyntax.c
Original file line number Diff line number Diff line change
Expand Up @@ -3069,11 +3069,13 @@ bool isyntax_open(isyntax_t* isyntax, const char* filename, bool init_allocators
// (I guess this is related to the way the wavelet transform works.)
// Put another way: the highest (zoomed out levels) are shifted the to the bottom right
// (this is also reflected in the x and y coordinates of the codeblocks in the iSyntax header).
for (i32 scale = 1; scale < wsi_image->level_count; ++scale) {
isyntax_level_t* level = wsi_image->levels + scale;
for (i32 scale = 0; scale < wsi_image->level_count; ++scale) {
isyntax_level_t* level = wsi_image->levels + scale;
level->origin_offset_in_pixels = ((PER_LEVEL_PADDING << wsi_image->level_count) - PER_LEVEL_PADDING) >> scale;
level->width = wsi_image->width >> scale;
level->height = wsi_image->height >> scale;
float offset_in_pixels = (float) (get_first_valid_coef_pixel(scale - 1));
level->origin_offset_in_pixels = offset_in_pixels;
float offset_in_um_x = offset_in_pixels * wsi_image->levels[0].um_per_pixel_x;
float offset_in_um_x = offset_in_pixels * wsi_image->levels[0].um_per_pixel_x;
float offset_in_um_y = offset_in_pixels * wsi_image->levels[0].um_per_pixel_y;
level->origin_offset = (v2f){offset_in_um_x, offset_in_um_y};
}
Expand Down Expand Up @@ -3297,4 +3299,40 @@ void isyntax_destroy(isyntax_t* isyntax) {
file_handle_close(isyntax->file_handle);
}


void bgra_to_rgba(uint32_t *pixels, int tile_width, int tile_height) {
int num_pixels = tile_width * tile_height;
int num_pixels_aligned = (num_pixels / 4) * 4;

#if defined(__ARM_NEON)
for (int i = 0; i < num_pixels_aligned; i += 4) {
uint32x4_t bgra = vld1q_u32(pixels + i);
uint32x4_t b_mask = vdupq_n_u32(0x000000FF);
uint32x4_t r_mask = vdupq_n_u32(0x00FF0000);
uint32x4_t b = vandq_u32(bgra, b_mask);
uint32x4_t r = vandq_u32(bgra, r_mask);
uint32x4_t br_swapped = vorrq_u32(vshlq_n_u32(b, 16), vshrq_n_u32(r, 16));
uint32x4_t ga_alpha_mask = vdupq_n_u32(0xFF00FF00);
uint32x4_t ga_alpha = vandq_u32(bgra, ga_alpha_mask);
uint32x4_t rgba = vorrq_u32(ga_alpha, br_swapped);
vst1q_u32(pixels + i, rgba);
}
#elif defined(__SSE2__)
for (int i = 0; i < num_pixels_aligned; i += 4) {
__m128i bgra = _mm_loadu_si128((__m128i*)(pixels + i));
__m128i b_mask = _mm_set1_epi32(0x000000FF);
__m128i r_mask = _mm_set1_epi32(0x00FF0000);
__m128i b = _mm_and_si128(bgra, b_mask);
__m128i r = _mm_and_si128(bgra, r_mask);
__m128i br_swapped = _mm_or_si128(_mm_slli_epi32(b, 16), _mm_srli_epi32(r, 16));
__m128i ga_alpha_mask = _mm_set1_epi32(0xFF00FF00);
__m128i ga_alpha = _mm_and_si128(bgra, ga_alpha_mask);
__m128i rgba = _mm_or_si128(ga_alpha, br_swapped);
_mm_storeu_si128((__m128i*)(pixels + i), rgba);
}
#else
for (int i = num_pixels_aligned; i < num_pixels; ++i) {
uint32_t val = pixels[i];
pixels[i] = ((val & 0xff) << 16) | (val & 0x00ff00) | ((val & 0xff0000) >> 16) | (val & 0xff000000);
}
#endif
}
4 changes: 3 additions & 1 deletion src/isyntax/isyntax.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,15 @@ typedef struct isyntax_level_t {
i32 scale;
i32 width_in_tiles;
i32 height_in_tiles;
u64 width;
u64 height;
float downsample_factor;
float um_per_pixel_x;
float um_per_pixel_y;
float x_tile_side_in_um;
float y_tile_side_in_um;
u64 tile_count;
float origin_offset_in_pixels;
i32 origin_offset_in_pixels;
v2f origin_offset;
isyntax_tile_t* tiles;
bool is_fully_loaded;
Expand Down
12 changes: 3 additions & 9 deletions src/isyntax_example.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,8 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "third_party/stb_image_write.h" // for png export



#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 print_isyntax_levels(isyntax_t* isyntax) {
int wsi_image_idx = libisyntax_get_wsi_image_index(isyntax);
Expand Down Expand Up @@ -74,9 +69,8 @@ int main(int argc, char** argv) {
assert(libisyntax_tile_read(isyntax, isyntax_cache, level, tile_x, tile_y, &pixels) == LIBISYNTAX_OK);

// convert data to the correct pixel format (bgra->rgba).
for (int i = 0; i < tile_height * tile_width; ++i) {
pixels[i] = bgra_to_rgba(pixels[i]);
}
bgra_to_rgba(pixels, tile_width, tile_height);

printf("Writing %s...\n", output_png);
stbi_write_png(output_png, tile_width, tile_height, 4, pixels, tile_width * 4);
printf("Done writing %s.\n", output_png);
Expand All @@ -87,4 +81,4 @@ int main(int argc, char** argv) {

libisyntax_close(isyntax);
return 0;
}
}
69 changes: 69 additions & 0 deletions src/isyntax_example2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "libisyntax.h"
#include <stdint.h>
#include <assert.h>

#define STB_IMAGE_WRITE_IMPLEMENTATION

#include "third_party/stb_image_write.h" // for png export

#define LOG_VAR(fmt, var) printf("%s: %s=" fmt "\n", __FUNCTION__, #var, var)


int main(int argc, char **argv) {

if (argc <= 7) {
printf("Usage: %s <isyntax_file> <level> <x_coord> <y_coord> <width> <height> <output.png> - write a tile to output.png",
argv[0], argv[0]);
return 0;
}

char *filename = argv[1];

libisyntax_init();

isyntax_t *isyntax;
if (libisyntax_open(filename, /*is_init_allocators=*/0, &isyntax) != LIBISYNTAX_OK) {
printf("Failed to open %s\n", filename);
return -1;
}
printf("Successfully opened %s\n", filename);

int32_t level = atoi(argv[2]);
int32_t x_coord = atoi(argv[3]);
int32_t y_coord = atoi(argv[4]);
int32_t region_width = atoi(argv[5]);
int32_t region_height = atoi(argv[6]);
const char *output_png = argv[7];

LOG_VAR("%d", level);
LOG_VAR("%d", x_coord);
LOG_VAR("%d", y_coord);
LOG_VAR("%d", region_width);
LOG_VAR("%d", region_height);
LOG_VAR("%s", output_png);

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("example cache", 2000, &isyntax_cache) == LIBISYNTAX_OK);
assert(libisyntax_cache_inject(isyntax_cache, isyntax) == LIBISYNTAX_OK);

uint32_t *pixels = NULL;
assert(libisyntax_read_region(isyntax, isyntax_cache, level, x_coord, y_coord, region_width, region_height, &pixels) ==
LIBISYNTAX_OK);

// convert data to the correct pixel format (bgra->rgba).
bgra_to_rgba(pixels, region_width, region_height);

printf("Writing %s...\n", output_png);
stbi_write_png(output_png, region_width, region_height, 4, pixels, region_width * 4);
printf("Done writing %s.\n", output_png);

libisyntax_tile_free_pixels(pixels);
libisyntax_cache_destroy(isyntax_cache);
libisyntax_close(isyntax);
return 0;
}
Loading