Skip to content

C/C++ examples

Below are examples in C or C++ for working with the Acquire Zarr library. Have an example you'd like to share with the community? Submit a GitHub issue and include "Example:" in your title.

Example: Basic streaming to filesystem
/// @file stream-raw-to-filesystem.c
/// @brief Basic Zarr V3 streaming to filesystem
#include "acquire.zarr.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

int
main()
{
    // Configure stream settings
    ZarrArraySettings array = {
        .compression_settings = NULL,
        .data_type = ZarrDataType_uint16,
    };
    ZarrStreamSettings settings = {
        .store_path = "output_v3.zarr",
        .s3_settings = NULL,
        .version = ZarrVersion_3,
        .max_threads = 0, // use all available threads
        .arrays = &array,
        .array_count = 1,
    };

    // Set up dimensions (t, y, x)
    ZarrArraySettings_create_dimension_array(settings.arrays, 3);

    settings.arrays->dimensions[0] = (ZarrDimensionProperties){
        .name = "t",
        .type = ZarrDimensionType_Time,
        .array_size_px = 0,
        .chunk_size_px = 5,
        .shard_size_chunks = 2,
    };

    settings.arrays->dimensions[1] = (ZarrDimensionProperties){
        .name = "y",
        .type = ZarrDimensionType_Space,
        .array_size_px = 48,
        .chunk_size_px = 16,
        .shard_size_chunks = 1,
    };

    settings.arrays->dimensions[2] = (ZarrDimensionProperties){
        .name = "x",
        .type = ZarrDimensionType_Space,
        .array_size_px = 64,
        .chunk_size_px = 16,
        .shard_size_chunks = 2,
    };

    // Create stream
    ZarrStream* stream = ZarrStream_create(&settings);
    // Free Dimension array
    ZarrArraySettings_destroy_dimension_array(settings.arrays);

    if (!stream) {
        fprintf(stderr, "Failed to create stream\n");
        return 1;
    }

    // Create sample data
    const size_t width = 64;
    const size_t height = 48;
    uint16_t* frame = (uint16_t*)malloc(width * height * sizeof(uint16_t));

    // Write frames
    size_t bytes_written;
    for (int t = 0; t < 50; t++) {
        // Fill frame with a moving diagonal pattern
        for (size_t y = 0; y < height; y++) {
            for (size_t x = 0; x < width; x++) {
                // Create a diagonal pattern that moves with time
                // and varies intensity based on position
                int diagonal = (x + y + t * 8) % 32;

                // Create intensity variation
                uint16_t intensity;
                if (diagonal < 16) {
                    intensity = (uint16_t)((diagonal * 4096)); // Ramp up
                } else {
                    intensity = (uint16_t)((31 - diagonal) * 4096); // Ramp down
                }

                // Add some circular features
                int centerX = width / 2;
                int centerY = height / 2;
                int dx = x - centerX;
                int dy = y - centerY;
                int radius = (int)sqrt(dx*dx + dy*dy);

                // Modulate the pattern with concentric circles
                if (radius % 16 < 8) {
                    intensity = (uint16_t)(intensity * 0.7);
                }

                frame[y * width + x] = intensity;
            }
        }

        ZarrStatusCode status =
          ZarrStream_append(stream,
                            frame,
                            width * height * sizeof(uint16_t),
                            &bytes_written,
                            NULL);

        if (status != ZarrStatusCode_Success) {
            fprintf(stderr,
                    "Failed to append frame: %s\n",
                    Zarr_get_status_message(status));
            break;
        }
    }

    // Cleanup
    free(frame);
    ZarrStream_destroy(stream);
    return 0;
}

Download this example

Example: Multiscale streaming to filesystem
/// @file stream-raw-multiscale-to-filesystem.c
/// @brief Uncompressed streaming to a Zarr V3 store on the filesystem, with
/// multiple levels of detail.
#include "acquire.zarr.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

int
main()
{
    // Configure stream settings
    ZarrArraySettings array = {
        .compression_settings = NULL,
        .data_type = ZarrDataType_uint16,
        .multiscale = true,
    };
    ZarrStreamSettings settings = {
        .store_path = "output_v3_multiscale.zarr",
        .s3_settings = NULL,
        .version = ZarrVersion_3,
        .max_threads = 0, // use all available threads
        .arrays = &array,
        .array_count = 1,
    };

    // Set up 5D array (t, c, z, y, x)
    ZarrArraySettings_create_dimension_array(settings.arrays, 5);

    settings.arrays->dimensions[0] = (ZarrDimensionProperties){
        .name = "t",
        .type = ZarrDimensionType_Time,
        .array_size_px = 10,
        .chunk_size_px = 5,
        .shard_size_chunks = 2,
    };

    settings.arrays->dimensions[1] = (ZarrDimensionProperties){
        .name = "c",
        .type = ZarrDimensionType_Channel,
        .array_size_px = 8,
        .chunk_size_px = 4,
        .shard_size_chunks = 2,
    };

    settings.arrays->dimensions[2] = (ZarrDimensionProperties){
        .name = "z",
        .type = ZarrDimensionType_Space,
        .array_size_px = 6,
        .chunk_size_px = 2,
        .shard_size_chunks = 1,
    };

    settings.arrays->dimensions[3] = (ZarrDimensionProperties){
        .name = "y",
        .type = ZarrDimensionType_Space,
        .array_size_px = 48,
        .chunk_size_px = 16,
        .shard_size_chunks = 1,
    };

    settings.arrays->dimensions[4] = (ZarrDimensionProperties){
        .name = "x",
        .type = ZarrDimensionType_Space,
        .array_size_px = 64,
        .chunk_size_px = 16,
        .shard_size_chunks = 2,
    };

    // Create stream
    ZarrStream* stream = ZarrStream_create(&settings);
    // Free Dimension array
    ZarrArraySettings_destroy_dimension_array(settings.arrays);

    if (!stream) {
        fprintf(stderr, "Failed to create stream\n");
        return 1;
    }

    // Create sample data
    const size_t width = 64;
    const size_t height = 48;
    uint16_t* frame = (uint16_t*)malloc(width * height * sizeof(uint16_t));

    // Write frames
    size_t bytes_written;
    for (int i = 0; i < 10; i++) {
        // Fill frame with sample data
        for (size_t j = 0; j < width * height; j++) {
            frame[j] = i * 1000 + j;
        }

        ZarrStatusCode status =
          ZarrStream_append(stream,
                            frame,
                            width * height * sizeof(uint16_t),
                            &bytes_written,
                            NULL);

        if (status != ZarrStatusCode_Success) {
            fprintf(stderr,
                    "Failed to append frame: %s\n",
                    Zarr_get_status_message(status));
            break;
        }
    }

    // Cleanup
    free(frame);
    ZarrStream_destroy(stream);
    return 0;
}

Download this example

Example: Compressed streaming to filesystem
/// @file stream-compressed-to-filesystem.c
/// @brief Zarr V3 with LZ4 compression to filesystem
#include "acquire.zarr.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

int
main()
{
    // Configure compression
    ZarrCompressionSettings compression = {
        .compressor = ZarrCompressor_Blosc1,
        .codec = ZarrCompressionCodec_BloscLZ4,
        .level = 1,
        .shuffle = 1,
    };

    // Configure stream settings
    ZarrArraySettings array = {
        .compression_settings = &compression,
        .data_type = ZarrDataType_uint16,
    };
    ZarrStreamSettings settings = {
        .store_path = "output_v3_compressed.zarr",
        .s3_settings = NULL,
        .version = ZarrVersion_3,
        .max_threads = 0, // use all available threads
        .arrays = &array,
        .array_count = 1,
    };

    // Set up dimensions (t, y, x)
    ZarrArraySettings_create_dimension_array(settings.arrays, 3);

    settings.arrays->dimensions[0] = (ZarrDimensionProperties){
        .name = "t",
        .type = ZarrDimensionType_Time,
        .array_size_px = 0,
        .chunk_size_px = 5,
        .shard_size_chunks = 2,
    };

    settings.arrays->dimensions[1] = (ZarrDimensionProperties){
        .name = "y",
        .type = ZarrDimensionType_Space,
        .array_size_px = 48,
        .chunk_size_px = 16,
        .shard_size_chunks = 1,
    };

    settings.arrays->dimensions[2] = (ZarrDimensionProperties){
        .name = "x",
        .type = ZarrDimensionType_Space,
        .array_size_px = 64,
        .chunk_size_px = 16,
        .shard_size_chunks = 2,
    };

    // Create stream
    ZarrStream* stream = ZarrStream_create(&settings);
    // Free Dimension array
    ZarrArraySettings_destroy_dimension_array(settings.arrays);

    if (!stream) {
        fprintf(stderr, "Failed to create stream\n");
        return 1;
    }

    // Create sample data
    const size_t width = 64;
    const size_t height = 48;
    int centerX = width / 2;
    int centerY = height / 2;

    uint16_t* frame = (uint16_t*)malloc(width * height * sizeof(uint16_t));

    // Write frames
    size_t bytes_written;
    for (int t = 0; t < 50; t++) {
        // Fill frame with a moving diagonal pattern
        for (size_t y = 0; y < height; y++) {
            int dy = y - centerY;
            for (size_t x = 0; x < width; x++) {
                // Create a diagonal pattern that moves with time
                // and varies intensity based on position
                int diagonal = (x + y + t * 8) % 32;

                // Create intensity variation
                uint16_t intensity;
                if (diagonal < 16) {
                    intensity = (uint16_t)((diagonal * 4096)); // Ramp up
                } else {
                    intensity = (uint16_t)((31 - diagonal) * 4096); // Ramp down
                }

                // Add some circular features
                int dx = x - centerX;
                int radius = (int)sqrt(dx*dx + dy*dy);

                // Modulate the pattern with concentric circles
                if (radius % 16 < 8) {
                    intensity = (uint16_t)(intensity * 0.7);
                }

                frame[y * width + x] = intensity;
            }
        }

        ZarrStatusCode status =
          ZarrStream_append(stream,
                            frame,
                            width * height * sizeof(uint16_t),
                            &bytes_written,
                            NULL);

        if (status != ZarrStatusCode_Success) {
            fprintf(stderr,
                    "Failed to append frame: %s\n",
                    Zarr_get_status_message(status));
            break;
        }
    }

    // Cleanup
    free(frame);
    ZarrStream_destroy(stream);
    return 0;
}

Download this example

Example: Basic streaming to S3
/// @file stream-raw-to-s3.c
/// @brief Zarr V3 with uncompressed data to S3
#include "acquire.zarr.h"
#include <stdio.h>
#include <stdlib.h>

int main() {
    // Configure S3
    // Ensure that you have set your S3 credentials in the environment variables
    // AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and optionally AWS_SESSION_TOKEN
    ZarrS3Settings s3 = {
        .endpoint = "http://localhost:9000",
        .bucket_name = "my-bucket",
    };

    // Configure stream settings
    ZarrArraySettings array = {
        .compression_settings = NULL, // No compression
        .data_type = ZarrDataType_uint16,
    };
    ZarrStreamSettings settings = {
        .store_path = "output_v3_s3.zarr",
        .s3_settings = &s3,
        .version = ZarrVersion_3,
        .max_threads = 0, // use all available threads
        .arrays = &array,
        .array_count = 1,
    };

    // Set up dimensions (t, z, y, x)
    ZarrArraySettings_create_dimension_array(settings.arrays, 4);

    settings.arrays->dimensions[0] = (ZarrDimensionProperties){
        .name = "t",
        .type = ZarrDimensionType_Time,
        .array_size_px = 0,  // Unlimited
        .chunk_size_px = 5,
        .shard_size_chunks = 2
    };

    settings.arrays->dimensions[1] = (ZarrDimensionProperties){
        .name = "z",
        .type = ZarrDimensionType_Space,
        .array_size_px = 10,
        .chunk_size_px = 2,
        .shard_size_chunks = 1
    };

    settings.arrays->dimensions[2] = (ZarrDimensionProperties){
        .name = "y",
        .type = ZarrDimensionType_Space,
        .array_size_px = 48,
        .chunk_size_px = 16,
        .shard_size_chunks = 1
    };

    settings.arrays->dimensions[3] = (ZarrDimensionProperties){
        .name = "x",
        .type = ZarrDimensionType_Space,
        .array_size_px = 64,
        .chunk_size_px = 16,
        .shard_size_chunks = 2
    };

    // Create stream
    ZarrStream* stream = ZarrStream_create(&settings);
    // Free Dimension array
    ZarrArraySettings_destroy_dimension_array(settings.arrays);

    if (!stream) {
        fprintf(stderr, "Failed to create stream\n");
        return 1;
    }

    // Create sample data
    const size_t width = 64;
    const size_t height = 48;
    uint16_t* frame = (uint16_t*)malloc(width * height * sizeof(uint16_t));

    // Write frames
    size_t bytes_written;
    for (int i = 0; i < 10; i++) {
        // Fill frame with sample data
        for (size_t j = 0; j < width * height; j++) {
            frame[j] = i * 1000 + j;
        }

        ZarrStatusCode status =
          ZarrStream_append(stream,
                            frame,
                            width * height * sizeof(uint16_t),
                            &bytes_written,
                            NULL);

        if (status != ZarrStatusCode_Success) {
            fprintf(stderr, "Failed to append frame: %s\n",
                    Zarr_get_status_message(status));
            break;
        }
    }

    // Cleanup
    free(frame);
    ZarrStream_destroy(stream);
    return 0;
}

Download this example

Example: Compressed streaming to S3
/// @file stream-compressed-to-s3.c
/// @brief Stream data to a Zarr V3 store with Zstd compression data on S3
#include "acquire.zarr.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

int
main()
{
    // Configure compression
    ZarrCompressionSettings compression = {
        .compressor = ZarrCompressor_Blosc1,
        .codec = ZarrCompressionCodec_BloscZstd,
        .level = 1,
        .shuffle = 1,
    };

    // Configure S3
    // Ensure that you have set your S3 credentials in the environment variables
    // AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and optionally AWS_SESSION_TOKEN
    ZarrS3Settings s3 = {
        .endpoint = "http://localhost:9000",
        .bucket_name = "my-bucket",
    };

    // Configure stream settings
    ZarrArraySettings array = {
        .compression_settings = &compression,
        .data_type = ZarrDataType_uint16,
    };
    ZarrStreamSettings settings = {
        .store_path = "output_v3_compressed_s3.zarr",
        .s3_settings = &s3,
        .version = ZarrVersion_3,
        .max_threads = 0, // use all available threads
        .arrays = &array,
        .array_count = 1,
    };

    // Set up dimensions (t, y, x)
    ZarrArraySettings_create_dimension_array(settings.arrays, 3);

    settings.arrays->dimensions[0] = (ZarrDimensionProperties){
        .name = "t",
        .type = ZarrDimensionType_Time,
        .array_size_px = 0, // Unlimited
        .chunk_size_px = 5,
        .shard_size_chunks = 2,
    };

    settings.arrays->dimensions[1] = (ZarrDimensionProperties){
        .name = "y",
        .type = ZarrDimensionType_Space,
        .array_size_px = 48,
        .chunk_size_px = 16,
        .shard_size_chunks = 1,
    };

    settings.arrays->dimensions[2] = (ZarrDimensionProperties){
        .name = "x",
        .type = ZarrDimensionType_Space,
        .array_size_px = 64,
        .chunk_size_px = 16,
        .shard_size_chunks = 2,
    };

    // Create stream
    ZarrStream* stream = ZarrStream_create(&settings);
    // Free Dimension array
    ZarrArraySettings_destroy_dimension_array(settings.arrays);

    if (!stream) {
        fprintf(stderr, "Failed to create stream\n");
        return 1;
    }

    // Create sample data
    const size_t width = 64;
    const size_t height = 48;
    uint16_t* frame = (uint16_t*)malloc(width * height * sizeof(uint16_t));

    // Write frames
    size_t bytes_written;
    for (int t = 0; t < 50; t++) {
        // Fill frame with a moving diagonal pattern
        for (size_t y = 0; y < height; y++) {
            for (size_t x = 0; x < width; x++) {
                // Create a diagonal pattern that moves with time
                // and varies intensity based on position
                int diagonal = (x + y + t * 8) % 32;

                // Create intensity variation
                uint16_t intensity;
                if (diagonal < 16) {
                    intensity = (uint16_t)((diagonal * 4096)); // Ramp up
                } else {
                    intensity = (uint16_t)((31 - diagonal) * 4096); // Ramp down
                }

                // Add some circular features
                int centerX = width / 2;
                int centerY = height / 2;
                int dx = x - centerX;
                int dy = y - centerY;
                int radius = (int)sqrt(dx*dx + dy*dy);

                // Modulate the pattern with concentric circles
                if (radius % 16 < 8) {
                    intensity = (uint16_t)(intensity * 0.7);
                }

                frame[y * width + x] = intensity;
            }
        }

        ZarrStatusCode status =
          ZarrStream_append(stream,
                            frame,
                            width * height * sizeof(uint16_t),
                            &bytes_written,
                            NULL);

        if (status != ZarrStatusCode_Success) {
            fprintf(stderr,
                    "Failed to append frame: %s\n",
                    Zarr_get_status_message(status));
            break;
        }
    }

    // Cleanup
    free(frame);
    ZarrStream_destroy(stream);
    return 0;
}

Download this example

Example: Multiscale compressed streaming to S3
/// @file stream-compressed-multiscale-to-s3.c
/// @brief Multiscale Zarr V3 with compressed data to S3
#include "acquire.zarr.h"

#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

int
main()
{
    // Configure compression
    ZarrCompressionSettings compression = {
        .compressor = ZarrCompressor_Blosc1,
        .codec = ZarrCompressionCodec_BloscZstd,
        .level = 1,
        .shuffle = 1,
    };

    // Configure S3
    // Ensure that you have set your S3 credentials in the environment variables
    // AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and optionally AWS_SESSION_TOKEN
    ZarrS3Settings s3 = {
        .endpoint = "http://127.0.0.1:9000",
        .bucket_name = "my-bucket",
    };

    // Configure stream settings
    ZarrArraySettings array = {
        .compression_settings = &compression,
        .data_type = ZarrDataType_uint16,
        .multiscale = true,
    };
    ZarrStreamSettings settings = {
        .store_path = "output_v3_compressed_multiscale_s3.zarr",
        .s3_settings = &s3,
        .version = ZarrVersion_3,
        .max_threads = 0, // use all available threads
        .arrays = &array,
        .array_count = 1,
    };

    // Set up dimensions (t, z, y, x)
    ZarrArraySettings_create_dimension_array(settings.arrays, 4);

    settings.arrays->dimensions[0] = (ZarrDimensionProperties){
        .name = "t",
        .type = ZarrDimensionType_Time,
        .array_size_px = 0, // Unlimited
        .chunk_size_px = 5,
        .shard_size_chunks = 2,
    };

    settings.arrays->dimensions[1] = (ZarrDimensionProperties){
        .name = "z",
        .type = ZarrDimensionType_Space,
        .array_size_px = 10,
        .chunk_size_px = 2,
        .shard_size_chunks = 1,
    };

    settings.arrays->dimensions[2] = (ZarrDimensionProperties){
        .name = "y",
        .type = ZarrDimensionType_Space,
        .array_size_px = 48,
        .chunk_size_px = 16,
        .shard_size_chunks = 1,
    };

    settings.arrays->dimensions[3] = (ZarrDimensionProperties){
        .name = "x",
        .type = ZarrDimensionType_Space,
        .array_size_px = 64,
        .chunk_size_px = 16,
        .shard_size_chunks = 2,
    };

    // Create stream
    ZarrStream* stream = ZarrStream_create(&settings);
    // Free Dimension array
    ZarrArraySettings_destroy_dimension_array(settings.arrays);

    if (!stream) {
        fprintf(stderr, "Failed to create stream\n");
        return 1;
    }

    // Create sample data
    const size_t width = 64;
    const size_t height = 48;
    uint16_t* frame = (uint16_t*)malloc(width * height * sizeof(uint16_t));

    // Write frames
    size_t bytes_written;
    for (int t = 0; t < 10; t++) {
        // Fill frame with a moving diagonal pattern
        for (size_t y = 0; y < height; y++) {
            for (size_t x = 0; x < width; x++) {
                // Create a diagonal pattern that moves with time
                // and varies intensity based on position
                int diagonal = (x + y + t * 8) % 32;

                // Create intensity variation
                uint16_t intensity;
                if (diagonal < 16) {
                    intensity = (uint16_t)((diagonal * 4096)); // Ramp up
                } else {
                    intensity = (uint16_t)((31 - diagonal) * 4096); // Ramp down
                }

                // Add some circular features
                int centerX = width / 2;
                int centerY = height / 2;
                int dx = x - centerX;
                int dy = y - centerY;
                int radius = (int)sqrt(dx*dx + dy*dy);

                // Modulate the pattern with concentric circles
                if (radius % 16 < 8) {
                    intensity = (uint16_t)(intensity * 0.7);
                }

                frame[y * width + x] = intensity;
            }
        }

        ZarrStatusCode status =
          ZarrStream_append(stream,
                            frame,
                            width * height * sizeof(uint16_t),
                            &bytes_written,
                            NULL);

        if (status != ZarrStatusCode_Success) {
            fprintf(stderr,
                    "Failed to append frame: %s\n",
                    Zarr_get_status_message(status));
            break;
        }
    }

    // Cleanup
    free(frame);
    ZarrStream_destroy(stream);
    return 0;
}

Download this example

Example: Streaming multiple arrays to a Zarr store on the filesystem
/// @file stream-multiarray-to-filesystem.cpp
/// @brief Stream multiple arrays with different data types to filesystem
#include "acquire.zarr.h"

#include <cstdint> // for uint16_t, uint8_t
#include <cstdlib> // for rand()
#include <iostream>
#include <vector>

template<typename T>
void
fill_data(std::vector<uint8_t>& data)
{
    T* data_view = reinterpret_cast<T*>(data.data());
    size_t n_elements = data.size() / sizeof(T);

    for (size_t i = 0; i < n_elements; ++i) {
        data_view[i] = static_cast<T>(rand() % 65536);
    }
}

int
main()
{
    // Configure compression settings for different arrays
    ZarrCompressionSettings lz4_compression = {
        .compressor = ZarrCompressor_Blosc1,
        .codec = ZarrCompressionCodec_BloscLZ4,
        .level = 1,
        .shuffle = 1,
    };

    ZarrCompressionSettings zstd_compression = {
        .compressor = ZarrCompressor_Blosc1,
        .codec = ZarrCompressionCodec_BloscZstd,
        .level = 3,
        .shuffle = 2,
    };

    // Configure stream settings
    ZarrStreamSettings settings = {
        .store_path = "output_multiarray.zarr",
        .s3_settings = nullptr,
        .version = ZarrVersion_3,
        .max_threads = 0, // use all available threads
        .overwrite = true,
    };

    // Allocate arrays
    ZarrStatusCode status = ZarrStreamSettings_create_arrays(&settings, 3);
    if (status != ZarrStatusCode_Success) {
        std::cerr << "Failed to create arrays: "
                  << Zarr_get_status_message(status) << std::endl;
        return 1;
    }

    // Array 1: 5D uint16 array with LZ4 compression
    settings.arrays[0] = {
        .output_key = "path/to/uint16_array",
        .compression_settings = &lz4_compression,
        .data_type = ZarrDataType_uint16,
    };

    // Array 2: 3D float32 array with Zstd compression
    settings.arrays[1] = {
        .output_key = "a/float32/array",
        .compression_settings = &zstd_compression,
        .data_type = ZarrDataType_float32,
    };

    // Array 3: 3D uint8 array with no compression
    settings.arrays[2] = {
        .output_key = "labels",
        .compression_settings = nullptr,
        .data_type = ZarrDataType_uint8,
    };

    // Set up dimensions for Array 1: 5D (t, c, z, y, x)
    ZarrArraySettings_create_dimension_array(&settings.arrays[0], 5);
    settings.arrays[0].dimensions[0] = {
        .name = "t",
        .type = ZarrDimensionType_Time,
        .array_size_px = 0,
        .chunk_size_px = 5,
        .shard_size_chunks = 2,
    };
    settings.arrays[0].dimensions[1] = {
        .name = "c",
        .type = ZarrDimensionType_Channel,
        .array_size_px = 8,
        .chunk_size_px = 4,
        .shard_size_chunks = 2,
    };
    settings.arrays[0].dimensions[2] = {
        .name = "z",
        .type = ZarrDimensionType_Space,
        .array_size_px = 6,
        .chunk_size_px = 2,
        .shard_size_chunks = 1,
    };
    settings.arrays[0].dimensions[3] = {
        .name = "y",
        .type = ZarrDimensionType_Space,
        .array_size_px = 48,
        .chunk_size_px = 16,
        .shard_size_chunks = 1,
    };
    settings.arrays[0].dimensions[4] = {
        .name = "x",
        .type = ZarrDimensionType_Space,
        .array_size_px = 64,
        .chunk_size_px = 16,
        .shard_size_chunks = 2,
    };

    // Set up dimensions for Array 2: 3D (z, y, x)
    ZarrArraySettings_create_dimension_array(&settings.arrays[1], 3);
    settings.arrays[1].dimensions[0] = {
        .name = "z",
        .type = ZarrDimensionType_Space,
        .array_size_px = 6,
        .chunk_size_px = 2,
        .shard_size_chunks = 1,
    };
    settings.arrays[1].dimensions[1] = {
        .name = "y",
        .type = ZarrDimensionType_Space,
        .array_size_px = 48,
        .chunk_size_px = 16,
        .shard_size_chunks = 1,
    };
    settings.arrays[1].dimensions[2] = {
        .name = "x",
        .type = ZarrDimensionType_Space,
        .array_size_px = 64,
        .chunk_size_px = 16,
        .shard_size_chunks = 2,
    };

    // Set up dimensions for Array 3: 3D (z, y, x)
    ZarrArraySettings_create_dimension_array(&settings.arrays[2], 3);
    settings.arrays[2].dimensions[0] = {
        .name = "z",
        .type = ZarrDimensionType_Space,
        .array_size_px = 6,
        .chunk_size_px = 2,
        .shard_size_chunks = 1,
    };
    settings.arrays[2].dimensions[1] = {
        .name = "y",
        .type = ZarrDimensionType_Space,
        .array_size_px = 48,
        .chunk_size_px = 16,
        .shard_size_chunks = 1,
    };
    settings.arrays[2].dimensions[2] = {
        .name = "x",
        .type = ZarrDimensionType_Space,
        .array_size_px = 64,
        .chunk_size_px = 16,
        .shard_size_chunks = 2,
    };

    // Create stream
    ZarrStream* stream = ZarrStream_create(&settings);

    if (!stream) {
        fprintf(stderr, "Failed to create stream\n");
        // Free dimension arrays before returning
        for (int i = 0; i < 3; i++) {
            ZarrArraySettings_destroy_dimension_array(&settings.arrays[i]);
        }
        ZarrStreamSettings_destroy_arrays(&settings);
        return 1;
    }

    // Create and write sample data for Array 1 (uint16, 5D)
    size_t uint16_size = 10 * 8 * 6 * 48 * 64;
    std::vector<uint8_t> uint16_data(uint16_size * sizeof(uint16_t));
    fill_data<uint16_t>(uint16_data);

    size_t bytes_written;
    status = ZarrStream_append(stream,
                               uint16_data.data(),
                               uint16_size * sizeof(uint16_t),
                               &bytes_written,
                               "path/to/uint16_array");

    if (status != ZarrStatusCode_Success) {
        std::cerr << "Failed to append uint16 data: "
                  << Zarr_get_status_message(status) << std::endl;
    }

    // Create and write sample data for Array 2 (float32, 3D)
    size_t float32_size = 6 * 48 * 64;
    std::vector<uint8_t> float32_data(float32_size * sizeof(float));
    fill_data<float>(float32_data);

    status = ZarrStream_append(stream,
                               float32_data.data(),
                               float32_size * sizeof(float),
                               &bytes_written,
                               "a/float32/array");

    if (status != ZarrStatusCode_Success) {
        std::cerr << "Failed to append float32 data: "
                  << Zarr_get_status_message(status) << std::endl;
    }

    // Create and write sample data for Array 3 (uint8, 3D)
    size_t uint8_size = 6 * 48 * 64;
    std::vector<uint8_t> uint8_data(uint8_size * sizeof(uint8_t));
    fill_data<uint8_t>(uint8_data);

    status = ZarrStream_append(stream,
                               uint8_data.data(),
                               uint8_size * sizeof(uint8_t),
                               &bytes_written,
                               "labels");

    if (status != ZarrStatusCode_Success) {
        std::cerr << "Failed to append uint8 data: "
                  << Zarr_get_status_message(status) << std::endl;
    }

    // Free dimension arrays
    for (int i = 0; i < 3; i++) {
        ZarrArraySettings_destroy_dimension_array(&settings.arrays[i]);
    }
    ZarrStreamSettings_destroy_arrays(&settings);

    // Tear down the stream
    ZarrStream_destroy(stream);

    return 0;
}

Download this example