C API
libkura exposes the engine as a small, stable C ABI for embedding in any language that can call C. Six functions, no exceptions across the boundary, additive only within a major version. Every release attaches libkura.a for Linux, Windows and macOS alongside kura.h.
The surface
#include "kura/kura.h"
typedef struct {
int ua;
int allow_visual_risk;
const char* doc_lang;
const char* password;
const char* output_condition_identifier;
const char* dest_profile;
size_t dest_profile_len;
int verify_only;
const unsigned char* invoice_xml;
size_t invoice_xml_len;
const char* invoice_profile;
const char* invoice_filename;
/* Added in 1.2; zero means off or unset. */
const char* output_condition_info;
const char* output_condition_registry;
const char* vt_records;
int analyze;
int outline_fonts;
int linearize;
double image_max_ppi;
double raster_dpi;
int rasterize_all_pages;
const char* preflight_profile; /* profile JSON text */
const unsigned char* embed_source; /* attached as the source file, PDF/A-3 */
size_t embed_source_len;
const char* embed_source_name;
const char* embed_source_mime;
const char* font_folders; /* newline-separated folders */
const kura_ocr_page* ocr_pages; /* words to lay down as invisible text */
size_t ocr_page_count;
} kura_options;
typedef struct {
const char* code;
const char* detail;
int severity; /* 1 info, 2 warning, 3 error */
int fixed;
const int* pages; /* 1-based; empty = whole document */
size_t page_count;
} kura_issue;
typedef struct {
int ok;
const unsigned char* pdf;
size_t pdf_len;
const char* error_code;
const char* error;
const char* suggested_level;
int compliant;
size_t findings;
const kura_issue* issues;
size_t issue_count;
const kura_issue* analysis;
size_t analysis_count;
} kura_result;
typedef struct {
int ok;
const char* error_code;
const char* error;
int einvoice;
const char* standard;
const char* profile;
const char* document_type;
const char* attachment;
const unsigned char* xml;
size_t xml_len;
int consistent;
const char* const* problems;
size_t problem_count;
const char* const* warnings;
size_t warning_count;
} kura_invoice;
kura_result* kura_convert(const unsigned char* data, size_t size, const char* level,
const kura_options* options);
void kura_result_free(kura_result* result);
const char* kura_version(void);
int kura_verify_password(const unsigned char* data, size_t size, const char* password);
kura_invoice* kura_read_invoice(const unsigned char* data, size_t size, const char* password);
void kura_invoice_free(kura_invoice* invoice);
const char* kura_engine_name(void);kura_convertconverts memory to memory.levelis any target as a string,optionsmay beNULLfor the defaults. It returnsNULLonly when the result object itself could not be allocated; every other failure, a bad level, an encrypted file, a rejected document, comes back on the result withok == 0anderror_codeset.- Zero the options struct before setting fields. A null pointer field means "not set".
verify_onlyruns check mode:pdfstays empty andcompliantandfindingsare filled in.- The
pdfbuffer is owned by the result. Copy it out beforekura_result_free, which releases everything the result points at. error_codevalues are listed on Rejection codes;suggested_levelis set for the rejections that have one.issueslists every finding of the run,analysisthe census and profile hits whenanalyzeorpreflight_profileis set. Each entry carries its severity and the 1-based pages it concerns; an empty page list means the whole document.preflight_profiletakes the JSON text of a profile; its fix steps apply unlessverify_onlyis set.font_foldersnames folders searched, recursively, for a font file whose name matches a non-embedded font before a substitute is used.ocr_pageshands the engine recognized words in PDF points from the top-left corner of the page; they become an invisible text layer.kura_verify_passwordanswers whether a password opens the document.kura_read_invoiceextracts and checks an e-invoice payload;consistentis 0 whenproblemsis non-empty.
A complete example
#include <stdio.h>
#include <stdlib.h>
#include "kura/kura.h"
int main(void) {
FILE* f = fopen("in.pdf", "rb");
if (!f) return 1;
fseek(f, 0, SEEK_END);
long n = ftell(f);
fseek(f, 0, SEEK_SET);
unsigned char* data = malloc(n);
fread(data, 1, n, f);
fclose(f);
kura_options opt = {0};
opt.ua = 1;
opt.doc_lang = "en-US";
kura_result* r = kura_convert(data, n, "2a", &opt);
if (!r) return 1;
if (!r->ok) {
fprintf(stderr, "%s: %s\n", r->error_code, r->error);
if (r->suggested_level) fprintf(stderr, "try level %s\n", r->suggested_level);
kura_result_free(r);
return 2;
}
FILE* out = fopen("out.pdf", "wb");
fwrite(r->pdf, 1, r->pdf_len, out);
fclose(out);
printf("converted with %s %s\n", kura_engine_name(), kura_version());
kura_result_free(r);
free(data);
return 0;
}Compile against a release archive, which ships libkura.a, libkura_raster.a and libpdfium.a under lib/:
cc demo.c -I include -L lib -lkura -lkura_raster -lpdfium \
-lqpdf -lfreetype -lopenjp2 -ljpeg -lpng -lz -llcms2 -lstdc++ -o demoThe three archives carry the engine and PDFium; qpdf, FreeType, OpenJPEG, libjpeg, libpng, zlib and Little CMS come from your system or from your own static builds of them. On macOS add -framework CoreFoundation -framework CoreGraphics -framework AppKit for PDFium.
Threading
A kura_result is not shared between threads. Independent calls producing independent results may run concurrently, with one exception: rasterization. PDFium keeps process-global state, so calls that flatten transparency or rasterize pages must be serialized across the process. Builds without PDFium have no such restriction.
What the C API does not expose
Signing is a host callback in the C++ interface; the C ABI does not carry function pointers, so sign the output with your own PKCS#7 tooling. Two-document compare is a CLI feature. The ABI grows additively; fields are appended to the option struct, never reordered.