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

C Bindings #1444

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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 library/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ target_include_directories(libf3d
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/private>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/plugin>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/plugin>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
if (F3D_USE_EXTERNAL_NLOHMANN_JSON)
target_link_libraries(libf3d PRIVATE nlohmann_json::nlohmann_json)
Expand Down
103 changes: 103 additions & 0 deletions library/public/image_c_api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#ifndef F3D_C_API_H
#define F3D_C_API_H

#include "export.h" // Ensure F3D_EXPORT is defined
Meakk marked this conversation as resolved.
Show resolved Hide resolved

#ifdef __cplusplus
extern "C" {
#endif

/* Structure representing a 3D point */
typedef struct {
float x;
float y;
float z;
} f3d_point3_t;

/* Structure representing a 3D vector */
typedef struct {
float x;
float y;
float z;
} f3d_vector3_t;

/* Forward declaration of the f3d_image structure */
typedef struct f3d_image f3d_image_t;

/* Function to create a new image object */
F3D_EXPORT f3d_image_t* f3d_image_new(void);
Meakk marked this conversation as resolved.
Show resolved Hide resolved

/* Function to delete an image object */
F3D_EXPORT void f3d_image_delete(f3d_image_t* img);

/* Function to set the resolution of an image */
F3D_EXPORT void f3d_image_set_resolution(f3d_image_t* img, unsigned int width, unsigned int height);

/* Function to get the width of an image */
F3D_EXPORT unsigned int f3d_image_get_width(f3d_image_t* img);

/* Function to get the height of an image */
F3D_EXPORT unsigned int f3d_image_get_height(f3d_image_t* img);

/* Function to get the number of channels in an image */
F3D_EXPORT unsigned int f3d_image_get_channel_count(f3d_image_t* img);

/* Function to get the type of channels in an image */
F3D_EXPORT unsigned int f3d_image_get_channel_type(f3d_image_t* img);

/* Function to get the size of the channel type in an image */
F3D_EXPORT unsigned int f3d_image_get_channel_type_size(f3d_image_t* img);

/* Function to set the content of an image from a buffer */
F3D_EXPORT void f3d_image_set_content(f3d_image_t* img, void* buffer);

/* Function to get the content of an image as a buffer */
F3D_EXPORT void* f3d_image_get_content(f3d_image_t* img);

/* Function to compare two images and return the difference */
F3D_EXPORT int f3d_image_compare(f3d_image_t* img, f3d_image_t* reference, double threshold, f3d_image_t* diff, double* error);

/* Function to save an image to a file */
F3D_EXPORT void f3d_image_save(f3d_image_t* img, const char* path, int format);

/* Function to save an image to a buffer */
F3D_EXPORT unsigned char* f3d_image_save_buffer(f3d_image_t* img, int format, unsigned int* size);

/* Function to convert an image to a string representation for terminal output */
F3D_EXPORT const char* f3d_image_to_terminal_text(f3d_image_t* img);

/* Function to set metadata for an image */
F3D_EXPORT void f3d_image_set_metadata(f3d_image_t* img, const char* key, const char* value);

/* Function to get metadata from an image */
F3D_EXPORT const char* f3d_image_get_metadata(f3d_image_t* img, const char* key);

/* Function to get all metadata keys from an image */
F3D_EXPORT char** f3d_image_all_metadata(f3d_image_t* img, unsigned int* count);

/* Function to free metadata keys obtained from an image */
F3D_EXPORT void f3d_image_free_metadata_keys(char** keys, unsigned int count);

/* Function to create an image from a file */
F3D_EXPORT f3d_image_t* f3d_image_create_from_file(const char* path);

/* Function to create an image with specified parameters */
F3D_EXPORT f3d_image_t* f3d_image_create_with_params(unsigned int width, unsigned int height, unsigned int channelCount, unsigned int type);

/* Function to get the count of supported image formats */
F3D_EXPORT unsigned int f3d_image_get_supported_formats_count();

/* Function to get the list of supported image formats */
F3D_EXPORT const char** f3d_image_get_supported_formats();

/* Function to get a normalized pixel value from an image */
F3D_EXPORT double* f3d_image_get_normalized_pixel(f3d_image_t* img, int x, int y, unsigned int* count);

/* Function to free a normalized pixel value obtained from an image */
F3D_EXPORT void f3d_image_free_normalized_pixel(double* pixel);

#ifdef __cplusplus
}
#endif

#endif // F3D_C_API_H
166 changes: 166 additions & 0 deletions library/src/image_c_api.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#include "image_c_api.h"
#include "image.h"
#include <cstring>

struct f3d_image {
f3d::image img;
};

f3d_image_t* f3d_image_new(void) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this file (which includes and uses image.h) must be a C++ file. Only image_c_api.h have to be C only (and the unit test of course).

return new f3d_image_t();
}

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

void f3d_image_set_resolution(f3d_image_t* img, unsigned int width, unsigned int height) {
img->img.setResolution(width, height);
}

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<unsigned int>(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();
}

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

void f3d_image_save(f3d_image_t* img, const char* path, int format) {
f3d::image::SaveFormat save_format;
switch (format) {
case 0:
save_format = f3d::image::SaveFormat::PNG;
break;
case 1:
save_format = f3d::image::SaveFormat::JPG;
break;
case 2:
save_format = f3d::image::SaveFormat::TIF;
break;
case 3:
save_format = f3d::image::SaveFormat::BMP;
break;
default:
save_format = f3d::image::SaveFormat::PNG; // Default to PNG
break;
}
img->img.save(path, save_format);
}

unsigned char* f3d_image_save_buffer(f3d_image_t* img, int 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();
}

double* f3d_image_get_normalized_pixel(f3d_image_t* img, int x, int y, unsigned int* count) {
std::vector<double> pixel = img->img.getNormalizedPixel({x, y});
*count = pixel.size();
double* c_pixel = new double[pixel.size()];
std::copy(pixel.begin(), pixel.end(), c_pixel);
return c_pixel;
}

void f3d_image_free_normalized_pixel(double* pixel) {
delete[] pixel;
}
2 changes: 1 addition & 1 deletion library/testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,4 @@ if(Qt5_FOUND)
endif()

# make sure the libf3d API is compatible with C++11
set_target_properties(libf3dSDKTests PROPERTIES CXX_STANDARD 11)
set_target_properties(libf3dSDKTests PROPERTIES CXX_STANDARD 11)
97 changes: 97 additions & 0 deletions library/testing/test_image_c_api.c
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this file compiled ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not seem so, it needs to be added in library/testing/CMakeLists.txt

Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include <f3d/image.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

f3d_image_t* img = f3d_image_new();

f3d_image_set_resolution(img, 800, 600);
printf("Image resolution set to 800x600.\n");

unsigned int width = f3d_image_get_width(img);
unsigned int height = f3d_image_get_height(img);
printf("Image width: %u, height: %u\n", width, height);

unsigned int channels = f3d_image_get_channel_count(img);
printf("Image channel count: %u\n", channels);

size_t buffer_size = width * height * channels;
unsigned char* buffer = (unsigned char*)malloc(buffer_size);
if (!buffer) {
printf("Failed to allocate buffer.\n");
f3d_image_delete(img);
return 1;
}
memset(buffer, 255, buffer_size); // Set all pixels to white
f3d_image_set_content(img, buffer);
printf("Image content set to white.\n");

f3d_image_save(img, "output.png", 0);
printf("Image saved as output.png\n");

// Save image to buffer
unsigned int size;
unsigned char* save_buffer = f3d_image_save_buffer(img, 0, &size);
if (save_buffer) {
printf("Image saved to buffer, size: %u bytes.\n", size);
free(save_buffer);
} else {
printf("Failed to save image to buffer.\n");
}

// Set metadata
f3d_image_set_metadata(img, "Author", "TestUser");
printf("Metadata 'Author' set to 'TestUser'.\n");

// Get metadata
const char* author = f3d_image_get_metadata(img, "Author");
if (author) {
printf("Metadata 'Author': %s\n", author);
} else {
printf("Failed to get metadata 'Author'.\n");
}

// List all metadata
unsigned int count;
char** metadata_keys = f3d_image_all_metadata(img, &count);
if (metadata_keys) {
printf("Metadata keys (%u):\n", count);
for (unsigned int i = 0; i < count; ++i) {
printf(" %s\n", metadata_keys[i]);
free(metadata_keys[i]);
}
free(metadata_keys);
} else {
printf("Failed to list metadata keys.\n");
}

// Create a reference image for comparison
f3d_image_t* ref_img = f3d_image_new();
if (ref_img) {
f3d_image_set_resolution(ref_img, 800, 600);
f3d_image_set_content(ref_img, buffer);

// Compare images
double error;
f3d_image_t* diff_img = f3d_image_new();
int result = f3d_image_compare(img, ref_img, 0.0, diff_img, &error);
if (result == 0) {
printf("Images are identical.\n");
} else {
printf("Images differ with error: %f\n", error);
}

f3d_image_delete(diff_img);
f3d_image_delete(ref_img);
} else {
printf("Failed to create reference image.\n");
}

// Clean up
free(buffer);
f3d_image_delete(img);

return 0;
}