libHaru
| Language | C (usable from C++; bindings for other languages exist) |
|---|---|
| License | zlib license |
| Repository | github.com/libharu/libharu |
| Documentation | libHaru wiki |
| Depends on | zlib, libpng (both optional) |
| Read / write | no / yes |
libHaru generates PDF files from C: text in the standard 14 fonts or embedded TrueType and Type 1 fonts, lines and shapes, PNG and JPEG images, outlines, links and text annotations, compression and password protection. It’s small, portable and has a permissive license.
It can’t read or modify existing PDFs, has no layout engine (you position every line yourself) and its encryption only goes up to RC4 128-bit (revision 3), which is no longer secure. Use it for simple reports, labels and tickets generated from C code.
Installation#
# Debian / Ubuntu
sudo apt install libhpdf-dev
# macOS
brew install libharu
# Windows (vcpkg)
vcpkg install libharu
Link with -lhpdf. In CMake:
find_library(HPDF_LIBRARY NAMES hpdf REQUIRED)
target_link_libraries(myapp PRIVATE ${HPDF_LIBRARY})
Basic usage: create a PDF with text#
#include <hpdf.h>
#include <stdio.h>
static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void *user_data) {
fprintf(stderr, "libharu error 0x%04X, detail %u\n", (unsigned)error_no, (unsigned)detail_no);
}
int main(void) {
HPDF_Doc pdf = HPDF_New(error_handler, NULL);
if (!pdf) return 1;
HPDF_SetCompressionMode(pdf, HPDF_COMP_ALL);
HPDF_Page page = HPDF_AddPage(pdf);
HPDF_Page_SetSize(page, HPDF_PAGE_SIZE_A4, HPDF_PAGE_PORTRAIT);
HPDF_Font font = HPDF_GetFont(pdf, "Helvetica", NULL);
HPDF_Page_BeginText(page);
HPDF_Page_SetFontAndSize(page, font, 24);
HPDF_Page_TextOut(page, 60, HPDF_Page_GetHeight(page) - 80, "Hello, PDF!");
HPDF_Page_EndText(page);
// a line under the title
HPDF_Page_SetLineWidth(page, 1);
HPDF_Page_MoveTo(page, 60, HPDF_Page_GetHeight(page) - 90);
HPDF_Page_LineTo(page, 300, HPDF_Page_GetHeight(page) - 90);
HPDF_Page_Stroke(page);
HPDF_STATUS st = HPDF_SaveToFile(pdf, "hello.pdf");
HPDF_Free(pdf);
return st == HPDF_OK ? 0 : 1;
}
Coordinates are in points (1/72 inch) from the bottom-left corner.
How to write UTF-8 text with a TrueType font#
The standard fonts only cover Latin-1. For other scripts embed a TrueType font and use the UTF-8 encoder:
HPDF_UseUTFEncodings(pdf);
const char *name = HPDF_LoadTTFontFromFile(pdf, "DejaVuSans.ttf", HPDF_TRUE /*embed*/);
HPDF_Font font = HPDF_GetFont(pdf, name, "UTF-8");
HPDF_Page_BeginText(page);
HPDF_Page_SetFontAndSize(page, font, 14);
HPDF_Page_TextOut(page, 60, 700, "Zażółć gęślą jaźń · Привет");
HPDF_Page_EndText(page);
How to add an image#
HPDF_Image img = HPDF_LoadPngImageFromFile(pdf, "logo.png"); // or HPDF_LoadJpegImageFromFile
HPDF_Page_DrawImage(page, img, 60, 500,
HPDF_Image_GetWidth(img) / 2.0f, HPDF_Image_GetHeight(img) / 2.0f);
How to set metadata and protect a PDF with a password#
HPDF_SetInfoAttr(pdf, HPDF_INFO_TITLE, "Monthly report");
HPDF_SetInfoAttr(pdf, HPDF_INFO_AUTHOR, "Reports service");
HPDF_SetPassword(pdf, "owner-password", "user-password");
HPDF_SetEncryptionMode(pdf, HPDF_ENCRYPT_R3, 16); // RC4 128-bit
HPDF_SetPermission(pdf, HPDF_ENABLE_PRINT);
RC4 is broken; if you need real protection, post-process the file with QPDF (qpdf --encrypt user owner 256 -- in.pdf out.pdf).
Tips#
HPDF_Page_TextWidth(page, text)measures a string for alignment and manual line wrapping;HPDF_Page_TextRectwraps text inside a rectangle.HPDF_SaveToStreamplusHPDF_ReadFromStreamproduce the PDF in memory, e.g. to send it from a web server.- The error handler is called for every error; the default (NULL) handler ignores errors, so always pass one.