Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Add C Bindings #1892

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/actions/generic-ci/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ runs:
-DCMAKE_POLICY_DEFAULT_CMP0091=NEW
-DCMAKE_MODULE_PATH=${{ matrix.vtk_version != 'v9.2.6' && (runner.os != 'Windows' || matrix.vtk_version != 'v9.3.1') && inputs.optional_deps_label == 'optional-deps' && '$(pwd)/../dependencies/install/lib/cmake/OpenVDB/' || '' }}
-DCMAKE_PREFIX_PATH:PATH=$(pwd)/../dependencies/install/
-DF3D_BINDINGS_C=ON
-DF3D_BINDINGS_JAVA=${{ (runner.os != 'macOS' || inputs.cpu == 'arm64') && inputs.optional_deps_label == 'optional-deps' && 'ON' || 'OFF' }}
-DF3D_BINDINGS_PYTHON=${{ inputs.optional_deps_label == 'optional-deps' && 'ON' || 'OFF' }}
-DF3D_BINDINGS_PYTHON_GENERATE_STUBS=${{ inputs.optional_deps_label == 'optional-deps' && 'ON' || 'OFF' }}
Expand Down
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@ if(F3D_WINDOWS_BUILD_SHELL_THUMBNAILS_EXTENSION)
add_subdirectory(winshellext)
endif()

# Python bindings
option(F3D_BINDINGS_C "Create C bindings" ON)
if(F3D_BINDINGS_C)
add_subdirectory(c)
endif()

# Python bindings
option(F3D_BINDINGS_PYTHON "Create Python bindings" OFF)
if(F3D_BINDINGS_PYTHON)
Expand Down Expand Up @@ -310,6 +316,7 @@ function(f3d_report_variable f3d_var)
message(STATUS "${f3d_var}: ${${f3d_var}}")
endfunction()

f3d_report_variable(F3D_BINDINGS_C)
f3d_report_variable(F3D_BINDINGS_JAVA)
f3d_report_variable(F3D_BINDINGS_PYTHON)
f3d_report_variable(F3D_BUILD_APPLICATION)
Expand Down
47 changes: 47 additions & 0 deletions c/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 3.21)

project(f3d_c_api)

include(GNUInstallDirs)

# List of source files
set(F3D_C_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/image_c_api.cxx
)

# List of headers that will be installed
set(F3D_C_PUBLIC_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/image_c_api.h
)

add_library(f3d_c_api ${F3D_C_SOURCE_FILES})

target_link_libraries(f3d_c_api PUBLIC libf3d)

target_include_directories(f3d_c_api
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)

set_target_properties(f3d_c_api PROPERTIES
CXX_VISIBILITY_PRESET hidden
CXX_STANDARD 17
POSITION_INDEPENDENT_CODE ON
)

# testing
if(BUILD_TESTING)
add_subdirectory(testing)
endif()

# installing
install(TARGETS f3d_c_api
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT sdk EXCLUDE_FROM_ALL
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT sdk EXCLUDE_FROM_ALL
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT sdk EXCLUDE_FROM_ALL
)

install(FILES ${F3D_C_PUBLIC_HEADERS}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/f3d"
COMPONENT sdk
EXCLUDE_FROM_ALL)
154 changes: 154 additions & 0 deletions c/image_c_api.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#include "image_c_api.h"
#include "image.h"
#include <cstring>

struct f3d_image {
f3d::image img;
};

f3d_image_t* f3d_image_new_empty() {
return new f3d_image_t{f3d::image()};
}

f3d_image_t* f3d_image_new_params(
unsigned int width, unsigned int height, unsigned int channelCount, f3d_image_channel_type_t channelType)
{
return new f3d_image_t{ f3d::image(width, height, channelCount, static_cast<f3d::image::ChannelType>(channelType)) };
}

f3d_image_t* f3d_image_new_path(const char* path)
{
return new f3d_image_t{ f3d::image(path) };
}

void f3d_image_delete(f3d_image_t* img) {
delete img;
}

void f3d_image_get_normalized_pixel(f3d_image_t* img, int x, int y, double* pixel)
{
std::vector<double> d = img->img.getNormalizedPixel({ x, y });
std::copy(d.begin(), d.end(), pixel);
}

unsigned int f3d_image_get_width(f3d_image_t* img) {
return img->img.getWidth();
}

unsigned int f3d_image_get_height(f3d_image_t* img) {
return img->img.getHeight();
}

unsigned int f3d_image_get_channel_count(f3d_image_t* img) {
return img->img.getChannelCount();
}

unsigned int f3d_image_get_channel_type(f3d_image_t* img) {
return static_cast<f3d_image_channel_type_t>(img->img.getChannelType());
}

unsigned int f3d_image_get_channel_type_size(f3d_image_t* img) {
return img->img.getChannelTypeSize();
}

void f3d_image_set_content(f3d_image_t* img, void* buffer) {
img->img.setContent(buffer);
}

void* f3d_image_get_content(f3d_image_t* img) {
return img->img.getContent();
}

double f3d_image_compare(f3d_image_t* img, f3d_image_t* reference) {
return img->img.compare(reference->img);
}

void f3d_image_save(f3d_image_t* img, const char* path, f3d_image_save_format_t format)
{
img->img.save(path, static_cast<f3d::image::SaveFormat>(format));
}

unsigned char* f3d_image_save_buffer(f3d_image_t* img, f3d_image_save_format_t format, unsigned int* size) {
std::vector<unsigned char> buffer = img->img.saveBuffer(static_cast<f3d::image::SaveFormat>(format));
unsigned char* c_buffer = new unsigned char[buffer.size()];
std::copy(buffer.begin(), buffer.end(), c_buffer);
*size = buffer.size();
return c_buffer;
}

const char* f3d_image_to_terminal_text(f3d_image_t* img) {
static std::string result;
result = img->img.toTerminalText();
return result.c_str();
}

void f3d_image_set_metadata(f3d_image_t* img, const char* key, const char* value) {
img->img.setMetadata(key, value);
}

const char* f3d_image_get_metadata(f3d_image_t* img, const char* key) {
static std::string result;
result = img->img.getMetadata(key);
return result.c_str();
}

char** f3d_image_all_metadata(f3d_image_t* img, unsigned int* count) {
std::vector<std::string> metadata_keys = img->img.allMetadata();
*count = metadata_keys.size();
char** keys = new char*[metadata_keys.size()];
for (size_t i = 0; i < metadata_keys.size(); ++i) {
keys[i] = new char[metadata_keys[i].size() + 1];
strcpy(keys[i], metadata_keys[i].c_str());
}
return keys;
}

void f3d_image_free_metadata_keys(char** keys, unsigned int count) {
for (unsigned int i = 0; i < count; ++i) {
delete[] keys[i];
}
delete[] keys;
}

// Additional functions to match all functionalities from image.cxx
f3d_image_t* f3d_image_create_from_file(const char* path) {
return new f3d_image_t{ f3d::image(path) };
}

f3d_image_t* f3d_image_create_with_params(unsigned int width, unsigned int height, unsigned int channelCount, unsigned int type) {
f3d::image::ChannelType channel_type;
switch (type) {
case 0:
channel_type = f3d::image::ChannelType::BYTE;
break;
case 1:
channel_type = f3d::image::ChannelType::SHORT;
break;
case 2:
channel_type = f3d::image::ChannelType::FLOAT;
break;
default:
channel_type = f3d::image::ChannelType::BYTE; // Default to BYTE
break;
}
return new f3d_image_t{ f3d::image(width, height, channelCount, channel_type) };
}

unsigned int f3d_image_get_supported_formats_count() {
std::vector<std::string> formats = f3d::image::getSupportedFormats();
return formats.size();
}

const char** f3d_image_get_supported_formats() {
static std::vector<std::string> formats = f3d::image::getSupportedFormats();
static std::vector<const char*> c_formats;
c_formats.clear();
for (const auto& format : formats) {
c_formats.push_back(format.c_str());
}
return c_formats.data();
}

void f3d_image_free_normalized_pixel(double* pixel) {
delete[] pixel;
}
Loading
Loading