Freud Internals

This page describes the internal structure of the Freud template: what files you touch, what each one is for, and how to wire a new feature end to end.

For the external command contract (flags, commands, expected output), see Freud CLI Reference.


Template source layout

src/
├── main.c        ← entry point; parses args, dispatches to features
├── argsparse.c   ← CLI argument parsing (don't modify)
├── argsparse.h
├── configp.h     ← Config struct definition (read-only)
├── features.c    ← your feature implementations go here
├── features.h    ← your function declarations go here
├── utils.c       ← shared helpers (you may add helpers here)
└── utils.h
freud.manifest     ← list of commands to test against (add new commands here)

In general You modify: features.h, features.c, main.c, and freud.manifest, you may modify utils.c and utils.h to add helpers functions or argsparse.c, argsparse.h, configp.h if you need to implement more CLI options (respect the Freud CLI Reference). You can add new source files, if you desire to structure your code differently, don’t forget to update the build system with cmake -B build if you do.


The Config struct

src/configp.h defines the configuration parsed from command-line arguments. You receive a fully populated Config in main.c — never parse argv yourself.

typedef struct _config {
    int    debug_mode;                       // --debug flag
    char   command[MAX_LENGTH_COMMAND];      // -c <command>
    char*  filenames[MAX_FILE_COUNT];        // -f <path> (can repeat)
    char*  arguments[MAX_ARGUMENT_COUNT];   // additional arguments
} Config;

conf.filenames[0] is the first -f argument — the input image path.
conf.filenames[1] is the second -f (for commands that take two images).


Reading and writing images

All image I/O goes through the estia-image library. See Libraries for the full API and Image Data Structure for how pixels are laid out in memory.


Adding a new feature — the pattern

Every new feature requires four changes. Miss any one and the feature either won’t compile, won’t run, or won’t be tested by the CI.

1. Declare in src/features.h

void my_feature(char *source_path);

2. Implement in src/features.c

void my_feature(char *source_path) {
    unsigned char *data = NULL;
    int width, height, channels;
    read_image_data(source_path, &data, &width, &height, &channels);

    // ... your logic ...

    free(data);
}

3. Dispatch in src/main.c

if (strncmp(configuration.command, "my_feature", 10) == 0) {
    my_feature(conf.filenames[0]);
}

4. Register in freud.manifest

my_feature