# How to Integrate the Kanzi C++ API for Compression into Your Application

> Easily integrate Kanzi C++ API for compression into your application. Link libkanzi, set up data structures, and use the Compressor API to process your data efficiently.

- Repository: [flanglet/kanzi-cpp](https://github.com/flanglet/kanzi-cpp)
- Tags: how-to-guide
- Published: 2026-03-01

---

**To integrate the Kanzi C++ API for compression, link your application against `libkanzi`, include [`kanzi/api/Compressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/kanzi/api/Compressor.hpp), configure a `cData` struct with your desired transform and entropy codec, and execute the `initCompressor()`, `compress()`, and `disposeCompressor()` sequence to process data blocks.**

The Kanzi C++ library (`flanglet/kanzi-cpp`) provides a modular, high-performance lossless compression pipeline designed for modern C++ applications. Whether you require a stable ABI through the C API or prefer direct C++ class instantiation, integrating Kanzi requires understanding its transform-entropy architecture and proper initialization workflow.

## Understanding the Kanzi Compression Architecture

Kanzi implements a clear pipeline that processes data through distinct stages to maximize compression efficiency.

### The Pipeline Flow

```

Input → Transform(s) → Entropy Encoder → CompressedOutputStream → File/Memory

```

- **Transforms** (e.g., LZ, BWT, RLT) increase data redundancy before encoding. Implementations reside in `src/transform/` (see [`LZCodec.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/LZCodec.cpp), [`BWT.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/BWT.cpp), [`ZRLT.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/ZRLT.cpp)).
- **Entropy codecs** (Huffman, ANS0/1, Range, FPAQ) convert transformed symbols into bit-streams. These live in `src/entropy/` (e.g., [`HuffmanEncoder.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/HuffmanEncoder.cpp), [`FPAQEncoder.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/FPAQEncoder.cpp)).
- **`CompressedOutputStream`** ([`src/io/CompressedOutputStream.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/io/CompressedOutputStream.hpp)) buffers data, writes block headers (unless headerless mode is enabled), and forwards encoded bits to a file descriptor.
- **`Context`** ([`src/Context.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/Context.hpp)) serves as the central configuration holder, storing parameters such as block size, thread count, transform/entropy names, checksum mode, and headerless flags. All high-level objects (`BlockCompressor`, `BlockDecompressor`, and the C API) read settings from a `Context` instance.

### The C API Wrapper

The **C API** ([`src/api/Compressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/api/Compressor.hpp), [`src/api/Compressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/api/Compressor.cpp)) provides an ABI-stable wrapper around the C++ pipeline. This avoids exposing template-heavy internals while granting full control over compression options. The typical compress flow involves:

1. Fill a `cData` structure with parameters (transform, entropy, block size, jobs, checksum, headerless).
2. Call `initCompressor(&cData, FILE* dst, &cContext*)`, which creates a `CompressedOutputStream`, validates names, and stores the pointer in an opaque `cContext`.
3. For each block, invoke `compress(cContext, src, inSize, &outSize)`, which transforms, entropy-encodes, and writes the data.
4. Call `disposeCompressor(&cContext, &writtenBytes)` to flush pending data and free resources.

For pure C++ projects, you can bypass the C wrapper and instantiate `BlockCompressor` directly (see [`src/app/BlockCompressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/BlockCompressor.hpp)). This class builds a `Context` internally and exposes `compress(uint64& written)` to process entire input streams.

## Step-by-Step Integration Guide

### Build and Link the Library

Clone the repository and build the static (`libkanzi.a`) or shared (`libkanzi.so`/`.dll`) library using the provided CMake configuration. Link your target with `kanzi` (static) or `kanzi_shared` (shared) and include the `Threads::Threads` dependency.

**Key file:** [`CMakeLists.txt`](https://github.com/flanglet/kanzi-cpp/blob/main/CMakeLists.txt) – [link](https://github.com/flanglet/kanzi-cpp/blob/master/CMakeLists.txt)

### Include the Public Headers

For the C API:

```cpp
#include <kanzi/api/Compressor.hpp>

```

For the C++ class API:

```cpp
#include <kanzi/app/BlockCompressor.hpp>

```

Headers are installed under `include/kanzi/…` when running `make install`.

**Key files:** [`src/api/Compressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/api/Compressor.hpp) – [link](https://github.com/flanglet/kanzi-cpp/blob/master/src/api/Compressor.hpp), [`src/app/BlockCompressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/BlockCompressor.hpp) – [link](https://github.com/flanglet/kanzi-cpp/blob/master/src/app/BlockCompressor.hpp)

### Configure Compression Parameters

Fill a `cData` struct (C API) or `Context` object (C++). Example configuration for the C API:

```cpp
kanzi::cData params{};
strcpy(params.transform, "LZ");        // Transform chain
strcpy(params.entropy,   "ANS0");      // Entropy codec
params.blockSize = 1 << 16;            // 64 KiB blocks
params.jobs      = 1;                  // Thread count
params.checksum  = 32;                 // 32-bit checksum per block
params.headerless = 0;                 // Standard headered stream

```

**Key file:** [`src/api/Compressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/api/Compressor.hpp) – [link](https://github.com/flanglet/kanzi-cpp/blob/master/src/api/Compressor.hpp)

### Initialize and Compress

Initialize the compressor:

```cpp
kanzi::cContext* ctx = nullptr;
if (kanzi::initCompressor(&params, outFile, &ctx) != 0) {
    // Handle error
}

```

Compress data blocks in a loop:

```cpp
size_t outSize = 0;
kanzi::compress(ctx, srcBuffer, srcSize, &outSize);

```

**Key file:** [`src/api/Compressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/api/Compressor.cpp) – [link](https://github.com/flanglet/kanzi-cpp/blob/master/src/api/Compressor.cpp)

### Finalize and Cleanup

Call `disposeCompressor` to flush remaining data and retrieve total bytes written:

```cpp
size_t totalWritten = 0;
kanzi::disposeCompressor(&ctx, &totalWritten);

```

The output file now contains a valid Kanzi bit-stream (or raw blocks if `headerless` was enabled).

## Code Examples

### Minimal C API Example

```cpp
// compress_demo.cpp
#include <cstdio>
#include <cstring>
#include <kanzi/api/Compressor.hpp>

int main()
{
    FILE* out = fopen("example.knz", "wb");
    if (!out) return 1;

    kanzi::cData params{};
    strcpy(params.transform, "LZ");
    strcpy(params.entropy, "ANS0");
    params.blockSize = 1 << 16;
    params.jobs = 1;
    params.checksum = 32;
    params.headerless = 0;

    kanzi::cContext* ctx = nullptr;
    if (kanzi::initCompressor(&params, out, &ctx) != 0) {
        fclose(out);
        return 2;
    }

    const char* txt = "The quick brown fox jumps over the lazy dog.";
    size_t txtSize = strlen(txt);
    size_t outSize = 0;

    if (kanzi::compress(ctx, 
                        reinterpret_cast<const unsigned char*>(txt), 
                        txtSize, 
                        &outSize) != 0) {
        kanzi::disposeCompressor(&ctx, nullptr);
        fclose(out);
        return 3;
    }

    size_t flushed = 0;
    kanzi::disposeCompressor(&ctx, &flushed);
    fclose(out);
    return 0;
}

```

**Implementation details:**

- `cData` fields are validated and rewritten by `initCompressor` (see lines 96-108 in [`Compressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/Compressor.cpp)).
- Block sizes are automatically rounded to multiples of 16 (`pData->blockSize = (pData->blockSize + 15) & -16`).
- Error codes are defined in [`src/Error.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/Error.hpp).

### Pure C++ Class API Example

```cpp
// cpp_compress_demo.cpp
#include <fstream>
#include <kanzi/app/BlockCompressor.hpp>
#include <kanzi/Context.hpp>

int main()
{
    kanzi::Context ctx;
    ctx.putString("transform", "LZ");
    ctx.putString("entropy", "ANS0");
    ctx.putInt("blockSize", 1 << 16);
    ctx.putInt("jobs", 4);
    ctx.putInt("checksum", 32);
    ctx.putInt("headerless", 0);
    ctx.putString("outputName", "example_cpp.knz");
    ctx.putString("inputName", "input.txt");

    kanzi::BlockCompressor compressor(ctx);
    uint64_t written = 0;
    
    int result = compressor.compress(written);
    return (result == 0) ? 0 : 1;
}

```

**Notes:**

- `BlockCompressor` reads `inputName` and `outputName` from the `Context`. If omitted, it defaults to `stdin`/`stdout`.
- The heavy lifting (transform selection, entropy encoder creation) occurs inside `BlockCompressor::compress` (see [`src/app/BlockCompressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/BlockCompressor.cpp) around line 1125).

### Python Integration via C API

The repository includes a Python wrapper demonstrating cross-language usage:

```python
from kanzi import Compressor, KanziError
import tempfile

def compress_bytes(data: bytes) -> bytes:
    with tempfile.NamedTemporaryFile(delete=False) as tmp:
        with Compressor(tmp.name,
                       transform=b"LZ",
                       entropy=b"ANS0",
                       block_size=1<<16,
                       jobs=1,
                       checksum=32,
                       headerless=0) as c:
            c.compress(data)
        
        with open(tmp.name, "rb") as f:
            return f.read()

```

This wrapper internally invokes the C functions defined in [`src/api/Compressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/api/Compressor.cpp).

## Key Implementation Files

| Category | File | Purpose | Link |
|----------|------|---------|------|
| **Public C API** | [`src/api/Compressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/api/Compressor.hpp) | Declares `cData`, `cContext`, `initCompressor()`, `compress()`, `disposeCompressor()` | [View](https://github.com/flanglet/kanzi-cpp/blob/master/src/api/Compressor.hpp) |
| | [`src/api/Compressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/api/Compressor.cpp) | Implements C API wrapper, creates `CompressedOutputStream`, validates parameters | [View](https://github.com/flanglet/kanzi-cpp/blob/master/src/api/Compressor.cpp) |
| | `src/api/Decompressor.hpp/cpp` | Symmetric decompression API | [Decompressor.hpp](https://github.com/flanglet/kanzi-cpp/blob/master/src/api/Decompressor.hpp) |
| **C++ Class API** | [`src/app/BlockCompressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/BlockCompressor.hpp) | High-level C++ interface using `Context` | [View](https://github.com/flanglet/kanzi-cpp/blob/master/src/app/BlockCompressor.hpp) |
| | [`src/app/BlockCompressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/BlockCompressor.cpp) | Core compression logic, multi-threading support | [View](https://github.com/flanglet/kanzi-cpp/blob/master/src/app/BlockCompressor.cpp) |
| **I/O Layer** | `src/io/CompressedOutputStream.hpp/cpp` | Block buffering, header writing, bit-packing | [CompressedOutputStream.hpp](https://github.com/flanglet/kanzi-cpp/blob/master/src/io/CompressedOutputStream.hpp) |
| **Configuration** | [`src/Context.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/Context.hpp) | Key-value store for compression parameters | [View](https://github.com/flanglet/kanzi-cpp/blob/master/src/Context.hpp) |
| **Error Handling** | [`src/Error.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/Error.hpp) | Error code definitions for API returns | [View](https://github.com/flanglet/kanzi-cpp/blob/master/src/Error.hpp) |

## Summary

- **Link against `libkanzi`** (static or shared) built via the provided [`CMakeLists.txt`](https://github.com/flanglet/kanzi-cpp/blob/main/CMakeLists.txt), ensuring you link `Threads::Threads` for multi-threading support.
- **Choose your API layer**: Use [`kanzi/api/Compressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/kanzi/api/Compressor.hpp) for stable C ABI compatibility across compilers, or [`kanzi/app/BlockCompressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/kanzi/app/BlockCompressor.hpp) for direct C++ integration with `Context`-based configuration.
- **Configure via `cData` or `Context`**: Set `transform` (e.g., "LZ", "BWT"), `entropy` (e.g., "ANS0", "Huffman"), `blockSize` (rounded to multiples of 16), `jobs` (thread count), and `headerless` mode.
- **Execute the lifecycle**: `initCompressor()` → `compress()` (loop for blocks) → `disposeCompressor()` to flush buffers and retrieve total bytes written.
- **Handle errors**: Check return codes against definitions in [`src/Error.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/Error.hpp); validation of transform/entropy names occurs during `initCompressor`.

## Frequently Asked Questions

### Should I use the C API or the C++ BlockCompressor class?

Use the **C API** ([`src/api/Compressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/api/Compressor.hpp)) when you need ABI stability across different compiler versions or when binding to other languages like Python. The `cData` struct and opaque `cContext` pointer provide a clean, stable interface. Use the **C++ `BlockCompressor` class** ([`src/app/BlockCompressor.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/BlockCompressor.hpp)) for native C++ projects where you want direct access to the `Context` object and prefer object-oriented resource management without extern "C" linkage overhead.

### How do I enable multi-threaded compression?

Set the `jobs` parameter in your `cData` struct (C API) or call `ctx.putInt("jobs", 4)` in your `Context` object (C++ API). The `BlockCompressor` implementation in [`src/app/BlockCompressor.cpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/app/BlockCompressor.cpp) handles thread pool creation and block-level parallelism automatically. Note that you must link against `Threads::Threads` in your CMake configuration to support concurrent execution.

### Can I compress data without headers for custom protocols?

Yes. Set `params.headerless = 1` (C API) or `ctx.putInt("headerless", 1)` (C++ API). In headerless mode, `CompressedOutputStream` (defined in [`src/io/CompressedOutputStream.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/io/CompressedOutputStream.hpp)) skips writing the Kanzi file signature and block metadata. You must manually track block sizes and checksums if your protocol requires them, as the decompressor will need identical parameters to decode the raw bit-stream correctly.

### What error codes does the C API return?

The C API returns integer error codes defined in [`src/Error.hpp`](https://github.com/flanglet/kanzi-cpp/blob/main/src/Error.hpp). Common values include `ERR_OK` (0) for success, `ERR_INVALID_PARAM` for malformed transform or entropy names, and `ERR_IO` for file operation failures. During `initCompressor`, the library validates `cData` fields and rewrites them (e.g., rounding `blockSize` to multiples of 16) before allocating the `cContext` structure. Always check return values before proceeding to `compress()` calls.